CCPC2020 網路預選賽 0005 Lunch(SG博弈+質因數分解)
阿新 • • 發佈:2020-10-04
題意
給\(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}\)
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; }