洛谷——P1147 连续自然数和

原题链接
如果从数学的角度,我们考虑一下,其实没必要用到前缀和。因为是连续序列和,设首项为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;
}
发布了14 篇原创文章 · 获赞 3 · 访问量 148

猜你喜欢

转载自blog.csdn.net/IMDASHUAI/article/details/104846695