SCUT - 290 - PARCO的因数游戏 - 博弈论

https://scut.online/p/290

一个 N 个数的取数游戏,Kaildls 和 Parco 轮流操作,每次操作从 N 个数中取一个数 y 并把他变成 y-x(满足 x | y 且y),无法操作的人输。

假设 Kaildls 先手且两人都是用最优策略,请问最后谁会赢?

第一次学SG函数,要找的是每次能从石子堆中取走的数目,记录下来。

最后的Nim和为0是后手赢?

#include<bits/stdc++.h>
using namespace std;
#define ll long long

#define MAXN 1000005
#define N 1000005

//f[N]:可改变当前状态的方式,N为方式的种类,f[N]要在getSG之前先预处理
//SG[]:0~n的SG函数值
//S[]:为x后继状态的集合
vector<int> nextofSG[MAXN];
int f[N],SG[MAXN],S[MAXN];
void  getSG(int n){
    for(int i = 2; i <= n; i++){
        int l=nextofSG[i].size();
        //后继状态 最多有l 种
        for(int j=0;j<=l;j++){
            S[j]=0;
        }
        for(auto vi:nextofSG[i]){
            //vi:从i状态能取走的石子数
            S[SG[i-vi]]=1;
        }
        for(int j=0;j<=l;j++){
            if(!S[j]){
                SG[i] = j;
                break;
            }
        }
        //cout<<"SG["<<i<<"]="<<SG[i]<<endl;
    }

}

int a[1000005];

unsigned generateai(unsigned &n,unsigned &x,unsigned &y, unsigned &z){
    x=x^(x<<11);
    x=x^(x>>4);
    x=x^(x<<5);
    x=x^(x>>14);
    unsigned w=x^(y^z);
    x=y;
    y=z;
    z=w;
    return z;
}

int main(){
    unsigned n,x,y,z;
    for(int i=1;i<=1000000;i++){
        for(int j=i+i;j<=1000000;j+=i){
            nextofSG[j].push_back(i);
        }
    }
    getSG(1000000);
    for(int t=0;t<100;t++){
        cin>>n>>x>>y>>z;
        int sumSG=0;
        for(int i=0;i<n;i++){
            a[i]=generateai(n,x,y,z)%n+1;
            //cout<<a[i]<<endl;
            sumSG^=SG[a[i]];
        }
        //cout<<"!"<<sumSG<<endl;
        if(sumSG==0)
            cout<<"Parco"<<endl;
        else{
            cout<<"Kaildls"<<endl;
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/10421254.html