Everything Nim个人思路题解(Codeforces Round 941 (Div. 2))

题解

考虑当前面取完,只剩最后一堆时,这时该谁取,这个人只需要把最后一堆全取完,即可获胜,对于每个人,最好的方案都是让自己在剩最后一堆时先取,要想达成这个局面,则需要倒数第二堆是你的对手取完,当取完倒数第三堆,第二堆个数有两种情况:

1.  倒数第二堆剩余1:此时如果是B先取倒数第二堆,则最后一堆由A先取,A获胜,所以对于每个人,要控制到倒数第二堆时是对方先取

2.倒数第二堆剩余x个,x>1:此时如果是A先取倒数第二堆,则A可以取x-1个,倒数第二堆剩余一个,然后B只能把倒数第二堆取完,然后A先手取最后一堆,A获胜. 所以对于每个人,要控制到倒数第二堆时,是自己先取.

对于每一堆,如果这一堆需要对面先手取,如果上一堆是自己先取,则一定可以控制这一堆是自己后手取,所以上一堆一定要自己先手取.  如果这一堆需要自己先手取,则分为上一堆时剩余1,x(x>1)两种情况,同上...   以此类推如果推出到第一堆时,先手不满足必胜的条件,则是后手赢

代码

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=2e5+10;
int ssa[N];
 
int main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        vector<int>aa(1,0);
        for(int i=1;i<=n;i++){
            int a;
            cin>>a;
            aa.push_back(a);
        }
        sort(aa.begin()+1,aa.end());
        n=unique(aa.begin()+1,aa.end())-aa.begin();
        // for(int i=1;i<=n;i++)cout<<aa[i]<<' ';
        // cout<<endl;
        // cout<<1<<endl;
        for(int i=1;i<=n;i++)ssa[i]=aa[i]-aa[i-1];
 
        int t=1;//先手为1
        for(int i=n-2;i>=1;i--){
        //对于最后一堆,已经知道了到最后一堆时需要先手才能必胜,t直接设为1,从倒数第二堆(即n-2)开始递推
        
            if(t){
                // cout<<i<<ssa[i]<<endl;/**/
                if(ssa[i]==1){
                    t=0;
                }
            }else {
                t=1;
            }
        }
        if(t)cout<<"Alice";
        else cout<<"Bob";
        cout<<endl;
    }
}
 

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值