-
题目描述:
-
小明很喜欢数学,有一天他在做数学作业时,要求计算出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 #
此题为1352:和为S的两个数的加强版,前面做1352时候我们利用了头尾两个标志位对数组进行遍历,思路是如果和大于S,则把尾标记向前移动,如果和小于S,则被头标记向后移动。正好相等则记录下来。
这个题目初步看来没有什么思路,但是因为刚刚做过前面类似的题目,因此可以利用相似的方法。设置标志变量small=1,big=2,sum=small+big。对于某个给定的S,如果sum<S,big++,例如S=9,big++后等于3,1+2+3依然小于9,则big再++,如过和超过S,则small++,small朝前移动。如果small移动到(S+1)/2还没有结果,则说明该S不能用连续和来表示。
-
#include <stdio.h>
int main(){
int low, high,flag;
int sum, k;
while( scanf("%d",&k) != EOF ){
if( k<0 ) break;
low=1; high=2; flag=0; sum=3;
while( low<high ){
if( sum==k ){
flag = 1;
for( int i=low; i<=high; i++){
printf("%d",i);
if( i==high ) printf("\n");
else printf(" ");
}
high++;
sum+=high;
}else if( sum>k ){
sum -=low;
low++;
}else{
high++;
sum +=high;
}
}
if( !flag ) printf("Pity!\n");
printf("#\n");
}
return 0;
}
然后将剑指offer代码搬来修改下:
#include <stdio.h>
void print(int small,int big)
{
int i;
for(i = small;i <= big;i++){
if(i != big)
printf("%d ",i);
else {
printf("%d\n",i);
}
}
}
int main(){
int S;
int small,big;
int flag;
int i,sum;
while(scanf("%d",&S)!=EOF&&S>=0){
flag = 0;
small = 1;
big = 2;
sum = small + big;
while(small < (S+1)/2){
if(sum == S){
flag = 1;
print(small,big);
}
while(sum > S && small < (S+1)/2){
sum -= small;
small++;
if(sum == S){
flag = 1;
print(small,big);
}
}
big++;
sum += big;
}
if(flag == 0)
printf("Pity!\n");
printf("#\n");
}
return 0;
}
后来在网上看到另外一种思路,觉得不错,也在这里分享给大家。
S = ( a0 + aN)N/2 ---- 等差数列求和公式
= ( 2a0-1 + N )N /2
==> 2a0 = 2S/N - N + 1
==> 2S % N == 0 && N < sqrt(2S)
for N = [ 2 , sqrt(2S) )
if 2S % N == 0 && 2a0 % 2 == 0
show( a0 , N )