题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6892
思路:
最初的思路是这样:把长度作素因子分解,这样分解次数之和(可拆分次数)就可以视作为一堆石子,什么时候取完就是全为1的情况也就是最后状态,但是这样直接转化为尼姆游戏会与题目中所说的有所区别,分解一次,假设除m(从一堆中拿走任意多个素因子(素因子乘积为m)后)在题目中会形成m个堆,那么我们思考,既然被分解后会形成m个堆,这想法还对吗?我们可以这样思考,如果从中拿走任意非2质数,那么肯定会形成奇数个石子数量相同的堆,那么其实最后尼姆异或的结果仍是1个堆的值,新多出来的m-1个堆异或后为0。如果从中拿走2的任意次数,那么作用就是让尼姆异或的结果为0,这与从中拿走一个2的作用是相同的,故2的贡献只有1,因此结论分解形成m个堆稍作改进后就不会影响我们向尼姆博弈作的转化。
代码:
#include<bits/stdc++.h> using namespace std; const int MAXN = 31625; int prime[MAXN], cnt; bool vis[MAXN]; void Prime() { for(int i = 2; i <= MAXN; i++) { if(!vis[i]) { prime[++cnt] = i; } for(int j = 1; j <= cnt ; j++) { if(i * prime[j] > MAXN) break; vis[i * prime[j]] = 1; if(i % prime[j] == 0) break; //当 i是prime[j]的倍数时,i = kprime[j],如果继续运算 j+1,i * prime[j+1] = prime[j] * k prime[j+1],这里prime[j]是最小的素因子,当i = k * prime[j+1]时会重复,所以才跳出循环。 } } } int a[15], b[15]; int main() { Prime(); int t; cin >> t; while(t--) { memset(b, 0, sizeof(b)); int n; cin >> n; for(int i = 0; i < n; i++) cin>>a[i]; int ans = 0; for(int i = 0; i < n; i++){ if(a[i]%2 == 0){ while(a[i]%2 == 0){ a[i] >>=1; } b[i]++; } for(int j = 1; j <= cnt && prime[j] <= a[i]; j++){ if(a[i]%prime[j] == 0){ while(a[i] % prime[j] == 0){ b[i]++; a[i]/=prime[j]; } } } if(a[i] > 1){ b[i]++; } ans ^= b[i]; } if(ans){ puts("W"); } else{ puts("L"); } } }