连续自然数平方和
【题目描述】:
给你一个数X,询问有多少种连续自然数的平方和等于这个数,按照起始自然数由小到大的顺序,输出所有可能。
【输入描述】:
输入有多组,每组一行,一个数X
【输出描述】:
对于每组数据,输出多行;
第一行,一个数表示有多少种可能;
以下每行输出一种:第一个数A是连续多少个自然数,后面输出这些连续自然数。
【样例输入】
2030 68126
【样例输出】
2 4 21 22 23 24 3 25 26 27 1 4 129 130 131 132
【数据范围及描述】:
时间:1s 空间:128M
X<10^14
拿到这个题目,按照一般思路肯定是考虑能否直接暴力,但数据范围无情地拒绝了这一想法,那么我们只能用尺取法这一方法解决了。所谓尺取法,就是在一个数组中保留两个下标,一个在左一个在右,先将右边的下标往右移,直到满足或者超过题目条件时停止右移。接着将左边的坐标右移一位再,右边坐标从上一次的位置接着右移,如此反复。那么这题的思路就是:先将X读入(注意要用long long),接着枚举i和j,把j不断向右移,将i~j中的自然数的平方相加,知道加起来的值sum大于或等于X为止。如果此时sum正好等于X,那么i~j就是一个答案,用一个数组保存即可。无论sum是否大于X,最后一步操作都要将i*i减去,再将i右移一个单位。
AC代码:
#include<iostream> #include<cstdio> #include<cmath> #define ll long long using namespace std; ll n; int ans[1005],x[1005],y[1005]; void work(){ int t=0; ll sum=0; ll m=1,e=0; ll s=(ll)sqrt(n*1.0); while(1){ while(sum<n){ e++; sum+=(e*e); } if(e>s) break; if(sum==n){ ans[t]=e-m+1; x[t]=m; y[t]=e; t++; } sum=sum-(m*m); m++; } printf("%d\n",t); for(int i=0;i<t;i++) { printf("%d ",ans[i]); for(int j=x[i];j<=y[i];j++) { printf("%d ",j); } printf("\n"); } } int main(){ while(scanf("%lld",&n)!=EOF){ work(); } return 0; }
AC截图:![]()