书上讲了一种提高效率的方法。原始算法:用i遍历1到n-1,如果i到j的和等于n那么就输出相应的结果。我们可以发现当sum(i,j)=n时,继续j++,sum+=j,计算的sum肯定是大于n的,于是便在sum(i,j)=n输出结果后,sum-=i,再继续sum+=j等后续工作,这样避免了无用功。
#include <iostream> #include<cstdio> using namespace std; void f(int x){ int i=1,j=2,sum=i; while(i<=x/2){ if(sum>=x)break; else if(sum<x){ for(;j<=x/2+1;j++){ sum+=j; if(sum==x){ printf("%d~%d\n",i,j); sum-=i; i++; if(i>x/2)break; } else if(sum>x){ do{ sum-=i; i++; if(sum==x){ printf("%d~%d\n",i,j); break; } else if(sum<x)break; }while(i<=x/2&&sum>x); } } } } } int main() { int n; while(cin>>n){ f(n); } return 0; }
在51nod也发现了相关的问题:
http://www.51nod.com/onlineJudge/solutionRank.html#!problemId=1138
给出一个正整数N,将N写为若干个连续数字和的形式(长度 >= 2)。例如N = 15,可以写为1 + 2 + 3 + 4 + 5,也可以写为4 + 5 + 6,或7 + 8。如果不能写为若干个连续整数的和,则输出No Solution。
输入1个数N(3 <= N <= 10^9)。
输出连续整数中的第1个数,如果有多个按照递增序排列,如果不能分解为若干个连续整数的和,则输出No Solution。
分析:设m是连续的数字个数,那么第一位数字一定满足:,这是一个减函数,所以可以确定对应的查找范围。同时,当m时偶数时,n%m=m/2;当m是奇数时,。
#include <iostream> #include <cstdio> using namespace std; int midfind(int n){ int l=2,r=n/2,mid,ans=0; while(l<=r){ mid=(l+r)>>1; if(n/mid-mid/2>0){ ans=mid; l=mid+1; } else r=mid-1; } return ans; } int main() { //freopen("cin.txt","r",stdin); int n; while(cin>>n){ int len=midfind(n); bool flag=0; for(int i=len;i>=2;i--){ if((i&1)&&n%i==0){ printf("%d\n",n/i-i/2); flag=1; } else if(((i&1)==0)&&n%i==i/2){ printf("%d\n",n/i-i/2+1); flag=1; } } if(!flag) puts("No Solution"); } return 0; }