CF1839E 题解

· · 题解

题目分析

实质上是让你找必胜策略的简单博弈题。题意转化一下是让你每次选两个数换成它们的差,问最后会不会剩下一个数,根据样例和手玩从 n=2 开始向大推广,容易得出以下结论:

猜到之后很好证明:

所以做完了,随便写个背包判胜负即可。

代码

int n,a[305],sum,dp[305][90005],zt[305];

signed main()
{
    cin>>n; for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i];
    dp[0][0]=1;
    for(int i=1;i<=n;i++) {for(int j=a[i];j<=sum;j++) dp[i][j]|=dp[i-1][j-a[i]]; for(int j=0;j<=sum;j++) dp[i][j]|=dp[i-1][j];}
    if(sum&1||!dp[n][sum/2])
    {
        cout<<"First"<<endl; int na=0,nb=0;
        while(1)
        {
            for(int i=1;i<=n;i++) if(a[i]) {na=i; break;}
            cout<<na<<endl; cin>>nb; if(nb==0) return 0; 
            int kk=min(a[na],a[nb]); a[na]-=kk; a[nb]-=kk;
        }
    }
    cout<<"Second"<<endl;
    int na=n,nb=sum/2;
    while(na)
    {
        if(nb>=a[na]&&dp[na-1][nb-a[na]]) zt[na]=1,nb-=a[na]; na--;
    }
    while(1)
    {
        cin>>na; if(na==0) return 0;
        for(int i=1;i<=n;i++) if(a[i]&&zt[i]!=zt[na]) {nb=i; break;}
        cout<<nb<<endl; int kk=min(a[na],a[nb]); a[na]-=kk; a[nb]-=kk;
    }
}