题目
Problem Description
Given a sequence 1,2,3,......N, your job is to calculate all the possible sub-sequences that the sum of the sub-sequence is M.
Input
Input contains multiple test cases. each case contains two integers N, M( 1 <= N, M <= 1000000000).input ends with N = M = 0.
Output
For each test case, print all the possible sub-sequence that its sum is M.The format is show in the sample below.print a blank line after each test case.
Sample Input
20 10
50 30
0 0
Sample Output
[1,4]
[10,10]
[4,8]
[6,9]
[9,11]
[30,30]
暴力解法
这是最容易想到的一种解法,但超时了
#include <cstdio>
int main() {
int N, M, sum;
while (scanf("%d%d", &N, &M), (N != 0 && M != 0)) {
for (int i = 1;i <= N;i++) {
sum = 0;
for (int j = i;j <= N;j++) {
sum += j;
if (sum == M) {
printf("[%d, %d]\n", i, j);
}
}
}
printf("\n");
}
}
数学知识
如果想要进行一些优化,那就要补充一些数学知识了
考虑这样的一个连续的整数序列
- 以 n 为中间数,向左右分别取 m 个数
对这个序列求和
sum = (n-m) + (n-m+1) + ... + (n-1) + n + (n+1) + ... + (n+m-1) + (n+m) = (2m+1) × n
也就是说,如果一个数 X 能被 2m+1 整除,且 n = X / (2m+1)
那么这个数 X 就等于从 n-m 到 n+m 的连续整数序列的和
即 X = (n-m) + (n-m+1) + ... + (n-1) + n + (n+1) + ... + (n+m-1) + (n+m)
换句话说,如果一个数 X 能被一个奇数 i 整除,此时 n = x / i, m = (i-1)/2,
那么这个数 X 就等于从 x/i - (i-1)/2 到 x/i + (i-1)/2 的连续整数序列的和
- 以 n 和 n+1 为中间数,向两边分别取 m 个数
对这个序列求和
sum = (n-m) + (n-m+1) + ... + n + (n+1) + ... + (n+m+1) = (m+1)(2n+1)
也就是说,如果一个数 X 能被 2n+1 整除,且 n = X / (2m+2)
这里 x / (2m+2) 得到的结果实际上是 n 和 n+1 的平均数,由于舍弃了小数,所以正好等于 n
故可以用 (X - X / (2m+2) * (2m+2)) == 2m+2 作为判断条件
那么这个数 X 就等于从 n-m 到 n+m+1 的连续整数序列的和
即 X = (n-m) + (n-m+1) + ... + n + (n+1) + ... + (n+m+1)
代码优化
有了上面的数学知识,我们就可以这样来写
对于 1,2,3,4,···,n 这样的连续整数序列,
我们首先要确定子序列可能的最大长度,
然后,根据长度,依次判断是否存在该长度对应的子序列
#include<stdio.h>
int main() {
int n, m, i;
while (scanf("%d%d", &m, &n), m + n) {
// n 子序列之和
// i 子序列长度
// n / i 子序列的中间那个数
// n / i - (i - 1) / 2 子序列的最左边的那个数
// 在保证子序列最左边的数大于零的条件下确定 i 的最大值
for (i = 1; n / i - (i - 1) / 2 > 0; i++);
// i 不为 0 && 子序列最右边的数不超过原数列边界
for (i--; i && n / i + i / 2 <= m; i--) {
// 当 n 不能整除 i && 2倍的余数等于长度
if ((n - n / i * i) * 2 == i)
printf("[%d,%d]\n", n / i - (i - 1) / 2, n / i + i / 2);
// 当 n 能整除 i && i 为奇数
if (!(n % i) && i % 2)
printf("[%d,%d]\n", n / i - (i - 1) / 2, n / i + i / 2);
}
putchar('\n');
}
return 0;
}