Hdu

题意:

给定n个数,两个人轮流进行操作,每次操作内容为选一个不等于1的数进行拆分,例如选的数字是l,k是l的因子,就可以拆分成l/k个k,当一方不能再拆分即为失败。问先手赢还是后手赢

题解:

第一反应就是博弈论,比赛时有考虑到质因数的个数,想到了唯一分解定理,但是最后都无功而返
想一想,什么样的数对先手有利,如果先手操作一次,后手可以复制一样的操作,那相当于没发生,对游戏结果没有产生影响
所以对于一个数,如果只能拆分成偶数个值,那添加的操作次数都是偶数个,对结果没有影响,即没有交换胜负手
但如果一个数可以拆出奇数个值,操作次数为奇数,就会发生交换胜负手

本质:线性筛(存质因素)+唯一分解定理(记录每个数=这个数的所有奇质因素的幂次+(2的倍数?1:0))
对于因子2而言,无论2的幂次是几,贡献只有1
比如数12,拆成6 和6,接下来我怎么操作,另一个人可以在另一堆做相同操作
最终问题转变成n堆物品,每次至少拿一个,也可以一次性拿完,问谁先赢,这就是nim博弈

代码:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5 + 100;
int v[maxn], prime[maxn];//v存质数,vis判断是不是质数
bool mp[maxn];
int primes(int n) {
    int m = 0;
    for (int i = 2; i <= n; i++) {
        if (v[i] == 0) {//i是质数
            v[i] = i; prime[++m] = i;
        }
        for (int j = 1; j <= m; j++) {
            if (prime[j] > v[i] || prime[j] > n / i)break;
            v[i*prime[j]] = prime[j];
        }
    }
    return m;
}
int cun[maxn], a[maxn];
int main()
{
    int n, m, ans, M;
    int t;
    cin>>t;
    M=primes(50010);
    while (t--){
        cin>>n;

        for (int i = 1; i <= n; i++)cun[i] = 0;
        for (int i = 1; i <= n; i++) {
            cin>>a[i];
            for (int j = 1; j <= M; j++) {
                if (a[i] == 1)break;
                if (prime[j] == 2&& a[i] % prime[j] == 0) {
                    cun[i]++;
                    while (a[i] % prime[j] == 0)
                    {
                        a[i] /= prime[j];
                    }
                    continue;
                }
                while (a[i]%prime[j]==0)
                {
                    cun[i]++;
                    a[i] /= prime[j];
                }
            }
            if (a[i] != 1)cun[i]++;
            if (i == 1)ans = cun[i];
            else ans ^= cun[i];
        }
        if (ans)printf("W\n");
        else printf("L\n");
    }
    return 0;
}