给一个正整数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
- 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");
- }
- }
- }
5050 26
69564669 12 (1617762 ~ 1617804)
4950 100
1000000000 2 (199999998 ~ 200000002)