题意
给(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
",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;
}