CCPC2020 网络预选赛 0005 Lunch(SG博弈+质因数分解)

传送门

题意

\(n\)个数\(a_1,a_2,...,a_n\),有两个选手,依次操作,对于一个数\(a_i\),每个人可以选择\(a_i\)的一个因数\(k\),将\(a_i\)分为\(k\)\(\frac{a_i}{k}\),如果一个人不能操作了,那么他就输了。问先手是否必赢。

题解

如果学过sg函数,那么结果就是\(sg(a_1)\oplus sg(a_2)\oplus ...\oplus sg(a_n)\)是否为真值。那么来考虑一下\(sg(x)\)的值,设\(d_1,d_2,...,d_k\)\(x\)的因数,那么\(x\)可以到达的状态就是\(d_1\)\(\frac{x}{d_1}\)\(d_2\)\(\frac{x}{d_2}\),……,\(d_k\)\(\frac{x}{d_k}\)\(sg(x)\)的值就是这几个状态的异或和。对于\(d_i\)\(\frac{x}{d_i}\)这个状态,它的\(sg\)值就是\(d_i\)\(sg(\frac{x}{d_i})\)的异或和。如果\(d_i\)是偶数,那么这个状态的\(sg\)值就是\(0\);否则这个状态的\(sg\)值就是\(sg(\frac{x}{d_i})\)。根据这个结果,可以写一个暴力求\(sg\)函数来解决这个问题的程序:

int sg(int x){
    // cout<<"x="<<x<<endl;
    if(vis[x]) return f[x];
    unordered_map<int,bool> cnt;
    for(int i=1;i*i<=x;i++){
        if(x%i!=0) continue;
        int a=i,b=x/i;
        if(b%2==0||a==1) cnt[0]=1;
        else cnt[sg(a)]=1;
        if(i==x/i||i==1) continue;
        swap(a,b);
        if(b%2==0||a==1) cnt[0]=1;
        else cnt[sg(a)]=1;
    }
    for(int i=0;;i++)
        if(!cnt[i]){
            vis[x]=1;
            return f[x]=i;
        }
}

当然这个程序是会超时的,可以打表看看每个数的\(sg\)值,可以发现:如果\(x=2^{b_0}a_1^{b_1}a_2^{b_2}...a_k^{b_k}\),那么\(sg(x)=[b_0>0]+b_1+b_2+...+b_k\)。所以直接把这个\(sg\)函数的解法换成质因数分解就可以了。

代码

int n,a[11];
int prime[N],vis[N],cnt;

int sg(int x){
    vector<PII> vec;
    for(int i=1;i<=cnt&&prime[i]*prime[i]<=x;i++){
        if(x%prime[i]!=0) continue;
        vec.push_back({prime[i],0});
        while(x%prime[i]==0) vec.back().y++,x/=prime[i];
    }
    if(x>1) vec.push_back({x,1});
    int res=0;
    for(PII p:vec)
        if(p.x==2) res++;
        else res+=p.y;
    return res;
}

void Solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int res=0;
    for(int i=1;i<=n;i++) res^=sg(a[i]);
    printf("%s\n",res?"W":"L");
}

int main(){
    for(int i=2;i<=1e5;i++){
        if(!vis[i]) {prime[++cnt]=i;vis[i]=1;}
        for(int j=1;j<=cnt&&prime[j]*i<=1e5;j++){
            vis[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
    int T;scanf("%d",&T);
    while(T--) Solve();
    return 0;
}
posted @ 2020-09-27 16:42  BakaCirno  阅读(323)  评论(0编辑  收藏  举报