Codeforces Round #844 (Div. 1 + Div. 2, based on VK Cup 2022 - Elimination Round) D

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值