列出一個正整數表示成n(n>=2)個連續正整數之和的所有形式
阿新 • • 發佈:2019-01-04
一個正整數有可能可以被表示為n(n>=2)個連續正整數之和,如: 15=1+2+3+4+5 15=4+5+6 15=7+8
請編寫程式,根據輸入的任何一個正整數n,找出符合這種要求的所有連續正整數序列的個數C。 如:對於15,其輸出結果是3:對於16,其輸出結果是:0。
n=56789, C = 3
n=189909, C = 5
n=999, C= 7
程式設計思想:
這個問題看起來不是很簡單,需要設計一個演算法:
先講數學:
設等差數列:
an=a+(n-1)*d (這裡首項為a,公差d=1,第n項為an,前n項和為sn)
a1=a
an=a+n-1
sn=(a1+an)n/2=(2a-1+n)*n/2
再回到這個程式設計上來:
我們的輸入資料其實就是sn,需要找到以a開始的n個連續的遞增數列使得和為sn。
這裡我們可以用迴圈來判定,給定一個n,sn已知,就可以求出a,如果a為正整數那麼就可以找到等差數列的首項,加上n給定,d=1,那麼就可以寫出這個和式子。
進一步優化提高程式效率:這裡的n無須一直從2開始列舉下去,可以由sn=(2a-1+n)*n/2,所以a=sn/n-n/2+1/2,該式子為遞減函式,n越大,a越小,而a最小為1,故另a=1時可確定n的最大範圍。
令a=1,得二元一次方程(1/2+n/2)*n=sn,即n^2+n-2*sn=0,可得方程兩個根中取較大的根n=0.5*(-1+sqrt(1+8*sn)),從而確定n的最大列舉範圍。
程式碼如下:
#include<stdio.h> #include<iostream> #include<math.h> using namespace std; int main() { int n,s,an,i,ans,cnt,fg; double a1; while(scanf("%d",&n)!=EOF) { ans=0; int mm=0.5*(-1+sqrt(1+8*n)); //列舉的最大範圍 for(cnt=2;cnt<=mm;cnt++) { a1=(2*n+cnt-cnt*cnt)*1.0/(2.0*cnt); if(int(a1)==a1&&a1>0) { printf("%d=%d",n,int(a1)); for(i=1;i<=cnt-1;i++) { printf("+%d",int(a1+i)); } printf("\n"); ans++; } } if(ans==0)printf("None!\n"); else printf("%d\n",ans); } return 0; }