有\(n\)堆石子,现可以对一堆石子选择一个整数\(L,(L > 1)\),将这堆石子再分成\(L\)堆\(\frac{a_i}{L}\)的石子。
最后无法进行操作的人输掉。
问先手获胜还是后手获胜。
\(n\)这么小,一看就很难直接看出性质做题。
考虑用\(SG\)函数打表看看。
显然我们要对每个长度求\(SG\)函数。
\(SG[1] = 0\)
打表程序
int SG[35];
int sg(int x) {
if(SG[x] != -1) return SG[x];
unordered_map<int, int> mp;
vector<int> v;
for (ll i = 2; i * i <= x; i++) {
if (x % i) continue;
v.push_back(i);
if (i * i != x) v.push_back(x / i);
}
v.push_back(x);
for (int i = 0; i < v.size(); i++) {
if (v[i] % 2 == 0) mp[0]++;
else mp[sg(x / v[i])]++;
}
for (int i = 0;; i++) {
if (!mp[i]) return SG[x] = i;
}
}
int main() {
memset(SG, -1, sizeof SG);
SG[1] = 0;
for (int i = 1; i <= 30; i++)
cout << i << ‘ ‘ << sg(i) << ‘\n‘;
}
得出结论
所以只要能得出\([1,10^9]\)的质因数分解即可。
考虑经典的试除法即可。
艰难卡常
2043ms
const int M = 4e4 + 5;
int prime[M];
int vis[M];
int cnt;
int euler_sieve(int n) {
int cnt = 0;
for (re int i = 2; i <= n; i++) {
if (!vis[i]) prime[cnt++] = i;
for (re int j = 0; j < cnt; j++) {
if (i * prime[j] > n) break;
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
return cnt;
}
int main() {
cnt = euler_sieve(M - 3);
int T = readint();
int n;
int res;
int tmp, x,tot;
while (T--) {
n = readint();
res = 0;
for (re int i = 0; i < n; i++) {
tmp = readint();
x = tmp;
tot = (x % 2 == 0);
while (x % 2 == 0) x /= 2;
for (re int i = 1; i < cnt; i++) {
if (x % prime[i]) continue;
while (x % prime[i] == 0) {
x /= prime[i];
tot++;
}
if ((ll)prime[i] * prime[i] > x) break;
}
if (x != 1 && x != 2) tot++;
res ^= tot;
}
if (res) puts("W");
else puts("L");
}
}
2020CCPC网络选拔赛 1005 Lunch 博弈论 打表 SG函数 找规律
原文:https://www.cnblogs.com/hznumqf/p/13732351.html