题目链接: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");
}
}
}
京公网安备 11010502036488号