题意
有一个前缀和是平方数的序列,也就是一个严格递增平方数的差分序列,奇数项丢了,给出偶数项,要求输出所有项。
思路
首先列出一个式子,对于题设差分序列中的一项c,必定要满足有$a^2-b^2=c$,即$(a-b) imes(a+b)=c$,那么现在已知c,如何定出a和b呢,很容易想到把c因式分解,使$(a-b)$,$(a+b)$为c的一对因子即可。设其中一个因子为x,不妨设x为一对之中大的那个因子,那么令$a+b=x$,$a-b=c/x$联立两式可解得,$2a=x+c/x$,$2b=x-c/x$。那么a,b存在的充分必要条件就是这对因子和(差)为偶数即可,换言之,一对和(差)为偶数的因子即可构造出c,且其他所有的数都不能构造出c(不会证明,可能是错的)。
推进到这里,我们就可以开始构造题目要求的序列了。针对每个数,我们都选择构造尽量小的平方数,这样保证在之后的构造中能够有更多的选择。在构造当前数的选择上,已经有的前缀和为now,那么当前数就为$b^2-now^2$。
进行上述步骤,哪步进行不下去就No。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+7; 4 int arr[maxn]; 5 vector<int> fac[maxn]; 6 long long ans[maxn]; 7 int main() 8 { 9 int n; 10 scanf("%d",&n); 11 n/=2; 12 for(int i=0;i<n;i++) 13 { 14 scanf("%d",&arr[i]); 15 for(int j=1;j<sqrt(arr[i]);j++) 16 { 17 if(arr[i]%j==0) 18 fac[i].push_back(arr[i]/j); 19 } 20 sort(fac[i].begin(),fac[i].end()); 21 } 22 int now=0; 23 bool flag=1; 24 for(int i=0;i<n;i++) 25 { 26 for(int j=0;j<fac[i].size();j++) 27 { 28 int a=fac[i][j],b=arr[i]/a; 29 if((a+b)%2) continue; 30 int aa=(a+b)/2,bb=(a-b)/2; 31 if(bb<=now) continue; 32 else{ 33 ans[i]=1LL*bb*bb-1LL*now*now; 34 now=aa; 35 break; 36 } 37 } 38 if(ans[i]==0) flag=0; 39 if(!flag) break; 40 } 41 if(!flag) puts("No"); 42 else { 43 puts("Yes"); 44 for(int i=0;i<n;i++) 45 { 46 printf("%lld %d ",ans[i],arr[i]); 47 } 48 } 49 50 }
后记
推公式真好玩。