序列和【牛客网】

题意:

给一个正整数N和长度L,找出一段长度大于等于L的连续非负整数,他们的和恰好为N。答案可能有多个,找出长度最小的那个。

例如:N=18 L=2:

5+6+7 = 18

3+4+5+6 = 18,输出更短的 5 6 7

数据范围:1 <= n <= 10^9, 2<= L<= 100

解法:暴力+剪枝

暴力枚举起始值和长度,双重for循环。由于需要找到长度尽量小的,所以从L开始枚举到100;起始值从0枚举到N。

剪枝:如果起始值为i,长度为len,则最后的值为i + len -1

从1开始到i的总和为f(i) = (1+i) * i /2

N = f(i+len - 1) - f(i),化简得到  i = N/(len - 1) - len/2

通过这个表达式可以缩小i的枚举范围。

代码:

#include <iostream>
using namespace std;

int main() {
    int N, L;
    int st, length;
    bool found = false;
    while (cin >> N >> L) { // 注意 while 处理多个 case        
        for(int len = L; len <= 100; len++) {
            int n = N/(len-1) - len/2;
            for(int i = n; i >= 0; i--) {
                if((2 * i + len - 1) * len == 2 * N) {
                    st = i;
                    length = len;
                    found = true;
                    break;
                }
            }
            if(found) break;
        }    

        if(found) {
            for(int i = 0; i < length - 1; i++) {
                printf("%d ", st + i);
            }
            printf("%d\n", st + length - 1);
        } else {
            printf("No\n");
        }
    }
}

case举例:

5050 26

69564669  12 (1617762 ~ 1617804)

4950 100

1000000000 2 (199999998 ~ 200000002)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值