1781D - Many Perfect Squares
分析
对于每组,若和均为完全平方数,则存在:
所以枚举所有,对于每个,枚举其所有“双因子对”,若两个因子之差为偶数,则一定能写成(a+b)(a-b)的形式。两个因子较大的为big,较小的为small,则a=(big+small)/2; b=(big-small)/2(解方程组)。对于此组a、b,
以f[i][x]表示第一层循环枚举到a[i]时,加上x可以具有的完全平方的个数。
若当前x是第一次被加入,则需要把当前第一指针和第二指针指向的两个数都统计到答案个数里:
否则,只需要把第二指针指向的数统计到答案个数里:
反思
两个数加同一个数再相减相当于原数相减,而n<=50的数据暗示了双重循环枚举所有数对的可行性。
没想到dp的状态表示——同一个x 下,一系列a[i]的完全平方数是唯一的。
代码实现
#include<bits/stdc++.h>
#define ll long long
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
int n;
ll a[53],ans,dif;
map<ll, int>f[53];
void solve(){
ans=1;
cin>>n;
rep(i,1,n){
cin>>a[i];
f[i].clear();
}
rep(i,1,n-1){
rep(j,i+1,n){
dif=a[j]-a[i];
rep(k,1,sqrt(dif)){
if(dif%k==0 && (dif/k-k)%2==0){
ll big=(dif/k+k)>>1;
ll small=(dif/k-k)>>1;
if(small*small<a[i]) continue;
ll x=small*small-a[i];
//a[i]+x=small*small, big同理
if(f[i][x]!=0) f[j][x]=max(f[j][x], f[i][x]+1);
else f[j][x]=2;
if(f[j][x]>ans){
ans=f[j][x];
}
/* cup-pyy的写法,与上几行写法等价(每个big/small对应着一个x)
//如果small曾经被作为big纳入,则只需要加上现在的big
if(f[i][small]!=0) f[j][big]=max(f[j][big], f[i][small]+1);
//否则得把当前small和big都纳入
else f[j][big]=2;
if(f[j][big]>ans){
ans=f[j][big];
}
*/
}
}
}
}
cout<<ans<<"\n";
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}