题意:
给定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;
}

京公网安备 11010502036488号