剑指Offer - 九度1354 - 和为S的连续正数序列
2013-11-23 02:02
- 题目描述:
-
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
- 输入:
-
输入有多组数据。
每组数据仅包括1个整数S(S<=1,000,000)。如果S为负数时,则结束输入。
- 输出:
-
对应每组数据,若不存在和为S的连续正数序列,则输出“Pity!”;否则,按照开始数字从小到大的顺序,输出所有和为S的连续正数序列。每组数据末尾以“#”号结束。
- 样例输入:
-
4 5 100 -1
- 样例输出:
-
Pity! # 2 3 # 9 10 11 12 13 14 15 16 18 19 20 21 22 #
题意分析:
题目要求求出对于一个数S,有多少种不同的连续正数序列加起来等于这个数S,数列至少要两个数。
比如
12 = 3 + 4 + 5
13 = 6 + 7
对于n个数a, a + 1, a + 2, ..., a + n - 1,加起来和sum = (a + a + n - 1) * n / 2;
所以对于某些n,我们要求2 * S = (2 * a + n - 1) * n的整数解。
因为题目要求所有数都是正整数,所以a >= 1,2 * a + n - 1 >= n + 1 > n,于是n < sqrt(2 * S),确定了范围限制在sqrt(1000000)内,也就是1000。,程序效率不成问题
对于2至[sqrt(2 * S)]的整数n,对应判断每一个能否求出整数解即可。有整数解的话,输出对应的连续数列。
注意题目要求按照开始数字从小到大输出结果。开头数字越小,项数也就越多,n也就越大,所以n要从sqrt(2 * S)往下递减。
时间复杂度O(sqrt(S)),空间复杂度O(1)。
1 // 652789 zhuli19901106 1354 Accepted 点击此处查看所有case的执行结果 1032KB 787B 80MS 2 // 20131172038 3 #include <cmath> 4 #include <cstdio> 5 using namespace std; 6 7 int main() 8 { 9 int x, y; 10 int tmp; 11 int s; 12 int res_count; 13 int i; 14 15 while(scanf("%d", &s) == 1 && s >= 0){ 16 if(s < 3){ 17 printf("Pity! # "); 18 continue; 19 } 20 21 s *= 2; 22 x = (int)sqrt(s); 23 res_count = 0; 24 while(x >= 2){ 25 if(s % x == 0){ 26 y = s / x; 27 if(y - x + 1 > 0 && ((y - x + 1) & 0x1) == 0){ 28 ++res_count; 29 tmp = (y - x + 1) >> 1; 30 printf("%d", tmp); 31 for(i = tmp + 1; i < tmp + x; ++i){ 32 printf(" %d", i); 33 } 34 printf(" "); 35 } 36 } 37 // watch out for the result order 38 --x; 39 } 40 if(res_count <= 0){ 41 printf("Pity! "); 42 } 43 printf("# "); 44 } 45 46 return 0; 47 }