题目描述:
对一个给定的自然数M,求出所有的连续的自然数段,这些连续的自然数段中的全部数之和为M。
分析:
(1)常见的方法是暴力去寻找,或者是打表记录下来,不过很可惜,这样做的时间复杂度是O(n^2)
(2)利用求和公式和求根公式:
设存在连续自然数,首项为A1,项数为m,即
A1+A2+...+Am=M
得到求和公式
A1*m+m*(m-1)/2=M
整理得到
m^2+(2*A1-1)*m-2M=0
很明显,这是一个关于m的一元二次方程,利用求根公式
m=(-b+sqrt(b^2-4*a*c)))/(2*a)
带入得:
m=(1-2*A1+sqrt((2*A1-1)^2+8*M))/2
因为要满足m为整数,那么就需要满足两个条件:
(1)sqrt((2*A1-1)^2+8*M)是整数;
(2)整个分子为偶数;
如果这两个条件都满足,那么就会存在m,因此可以开一个循环,从1遍历到n/2(想想为什么),对于每个i,当做A1来处理,看求出来的m是否为整数即可。
#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
int main()
{
int n,tt=1;
while(cin>>n)
{
printf("Case %d:\n",tt++);
for(int i=0;i<n/2;i++)
{
int a=i;
int w=(2*a-1)*(2*a-1)+8*n;
int k=(int)sqrt(w);
int m=k-2*a+1;
if(k*k!=w)
continue;
else if(m%2)
continue;
else
cout<<i<<" "<<i+m/2-1<<endl;
}
}
return 0;
}