CF1091H New Year and the Tricolore Recreation
\(n\) 个互相独立的游戏,所以考虑 SG 函数。但是看起来双方操作不同,好像不太能使用 SG?
其实是可以的!因为我们发现状态只和三个棋子间隔的两个距离有关,所以左边两个棋子右移等价于右边一个棋子左移!因此两个人的操作是相同的,都转换成了将右边的棋子左移或者将左边的棋子右移。而显然这两者之间没有任何关系,所以就从 \(n\) 个互相独立的游戏变成了 \(2n\) 个互相独立的游戏,每个游戏形如:有两个数 \(D\) 和 \(f\),每次可以选择一个整数 \(d\) 满足 \(d\neq f,d<D\) 且 \(d\) 是质数或可以表示成两个质数的乘积,将 \(D\) 减去 \(d\),直到无法操作为止。
现在就可以考虑 SG 函数了。设 \(SG[D]\) 表示如上游戏的 SG 函数,我们需要求至多 \(2\times 10^5\) 个 SG 函数值。但是好像根本没办法求啊!
既然没法求就考虑打表!对几个 \(f\) 进行打表之后发现 SG 函数不会超过 100,就可以上 bitset 了!具体的,先把质数和两个质数的乘积筛出来扔进 bitset 里,再令 \(f\) 这一位等于 0,然后就很好维护了。
code
#include <bits/stdc++.h>
using namespace std;
const int N=2e5;
bitset<N+5> ok,dp[105];
int n,ban,p[N+5],cnt,vis[N+5],SG[N+5];
signed main(){
cin>>n>>ban;
vis[1]=1;
for(int i=2;i<=N;i++){
if(!vis[i])p[++cnt]=i,ok[i]=1;
for(int j=1;j<=cnt&&p[j]*i<=N;j++){
vis[p[j]*i]=1;
if(i%p[j]==0)break;
}
}
for(int i=1;p[i]*p[i]<=N&&i<=cnt;i++)
for(int j=i;p[i]*p[j]<=N&&j<=cnt;j++)
ok[p[i]*p[j]]=1;
ok[ban]=0;
dp[0]=ok|(ok<<1);
for(int i=2;i<=N;i++){
while(dp[SG[i]][i])SG[i]++;
dp[SG[i]]|=(ok<<i);
}
int ans=0,x,y,z;
while(n--){
cin>>x>>y>>z;
ans^=SG[y-x-1]^SG[z-y-1];
}
if(ans)cout<<"Alice\nBob\n";
else cout<<"Bob\nAlice\n";
return 0;
}

浙公网安备 33010602011771号