原题链接
如果从数学的角度,我们考虑一下,其实没必要用到前缀和。因为是连续序列和,设首项为L,末项为R,序列和就为(L+R)(R-L+1)/2=M,即(L+R)(R-L+1)=2M。不妨令L+R和R+L+1分别为k1和k2,这样就可解出L,R。L=(k2-k1+1)/2, R=(k1+k2-1)/2,假定k1<k2。显然,k1+k2必须是奇数。而L!=R,也就k1!=1。所以得到代码。
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int m;
cin >> m;
int k1 = int(sqrt(2 * m));
for (; k1 > 1; k1--) {
if (2 * m % k1 == 0 && (k1 + 2 * m / k1) % 2) {
int k2=2*m/k1;
cout<<(k2-k1+1)/2<<" "<<(k1+k2-1)/2<<endl;
}
}
return 0;
}
我看题解的时候还有一个挺好的方法——尺取法,这里一并介绍一下。尺取法实际上是从小向大找,对于一个区间[l,r],如果和为sum,sum<m右指针就要向移动,sum>m左指针就要向左移动。正确性这里就不证明了。
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int m;
cin >> m;
int i=0,j=1;
int sum=1;
for(;i<=m/2;){
if(sum<m){
j++;
sum+=j;
}
else if(sum==m){
cout<<i<<" "<<j<<endl;
j++;
sum+=j;
}
else {
sum-=i;
i++;
}
}
return 0;
}