原题: http://codeforces.com/contest/1081/problem/E
题意:
有一个n(偶数)长的数组,每一个前缀和都是一个平方数,现在给出偶数位上的数,求原数组。(output any)
解析:
设原数组为{a,b,c,d},那么a是一个平方数,a+b是一个平方数,a+b+c是平方数,其中b已知,a,c可自己调节,那么如果a+b+c已经确定,则a+b越小越好,大了可以超过a+b+c的预设值了。所以可以贪心,找最小的a使a为平方数且a+b是平方数。
对于a分析:找一个最小的平方数a,使a+b为平方数。
对于c分析:已有a+b,找一个最小的c,使a+b+c为平方数,因为c可以调度,所以问题变成找最小的大于a+b的平方数x使x+d为平方数。
对于第一个数分析,设a[1]=a^2,a[1]+a[2]=x^2
,那么a[2]=x^2-a^2=(x+a)(x-a)
,显然,a[3]是可以调节的,所以a[1]+a[2]越小越好,即x^2越小越好,x=((x+a)+(x-a))/2
,也就是将a[2]分成两个数p,q
的乘积,且p+q
越小越好,那么|p-q|
越小越好,即将a[2]分成两个差较小的数的乘积
,那么从
开始往下找即可。
对于第三个数分析,设m=a[1]+a[2],c=a[3],x^2=m+c,d=a[4],其中m和d已知:
c>=1,所以知道了x的下限:
也就是说,除了|p-q|
需要较小以外,还需要
还有,p和q是(y-x)和(y+x),所以一定是同号的,那么d为偶数的时候,就一定是两个偶数的乘积,那么如果d不能整除4,一定不行。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define debug(i) printf("# %d\n",i)
LL a[100009];
LL deal1(LL val){
LL i=(LL)sqrt(val);
if(val%2)
for(i-=(1-i%2);i>=1;i-=2){//两个奇因子
if(val%i==0){
LL x=val/i-i;x/=2;
if(x*x<=0||x*x>1e13)continue;
return x*x;
}
}
else
for(i-=i%2;i>=2;i-=2){//两个偶因子
if(val%i==0&&val/i%2==0){
LL x=val/i-i;x/=2;
return x*x;
if(x*x<=0||x*x>1e13)continue;
}
}
return -1;
}
LL deal(LL m,LL val){
LL sub=2*(LL)sqrt(m+1);
LL i=(LL)sqrt(val);
if(val%2)
for(i-=(1-i%2);i>=1;i-=2){//两个奇因子
if(val%i==0&&(val/i-i>=sub)){
LL x=val/i-i;x/=2;
LL c=x*x-m;
if(c<=0||c>1e13)continue;
return c;
}
}
else
for(i-=i%2;i>=2;i-=2){//两个偶因子
if(val%i==0&&val/i%2==0&&(val/i-i>=sub)){
LL x=val/i-i;x/=2;
LL c=x*x-m;
if(c<=0||c>1e13)continue;
return c;
}
}
return -1;
}
int main(){
int n;scanf("%d",&n);
bool cant=0;
for(int i=2;i<=n;i+=2){
scanf("%lld",a+i);
if(a[i]%2==0&&a[i]%4)cant=1;
}
if(cant)return 0*printf("No\n");
a[1]=deal1(a[2]);
if(a[1]==-1)return 0*printf("No\n");
LL sum=a[1]+a[2];
for(int i=3;i<=n;i+=2){
a[i]=deal(sum,a[i+1]);
if(a[i]==-1){
return 0*printf("No\n");
}
sum+=a[i]+a[i+1];
}
printf("Yes\n");
for(int i=1;i<=n;i++)printf("%lld%c",a[i],(i==n?'\n':' '));
}