题解 ARC155D Avoid Coprime Game
题解 ARC155D Avoid Coprime Game
题意
给定一个可重集 ,保证 ,维护一个初始为 的整数 ,双方轮流操作,每次每人选择 中一个数 满足 ,然后 同时将 从 中删去,谁无法操作谁败。
对于所有 ,询问若先手一开始选择 则谁会获胜。
值域 ,集合大小 。
题解
分析
考虑一个局面 ,如果这个局面可以到达,那么显然 中所有不被 整除的数 都必须在 中,考虑哪些被 整除的数 ,如果之后的某次操作选择了 ,那么 显然不会变,所以实际上这些数对局面的影响本质是等效的,如果有 个这样的数,将这 个数从 中删去得到 ,用局面 表示,那么后面的每次决策要么就是同时改变 ,要么就是 ,所以本质上就是这两个游戏的组合,而 每次减一这个游戏的 SG 函数值显然就是 的奇偶性,所以可以得到 ,而值得注意的是, 仅由 唯一确定( 就是 中所有不能被 整除的数),不妨记 。
于是你可以把所有可到达局面简化成 ,而 就是值域范围,所以局面就被简化为可接受的数量了,接下来就是求所有的 了,局面连边数是 级别的,暴力连边即可,这个就是看 与 的 可能为哪些了,用莫反很好处理。(感觉没有啥更简单的方法了。。。)
总复杂度 。
参考代码
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=200005;
int A[maxn],CNT[maxn],sg[maxn];
int vis[maxn],mu[maxn],pri[maxn],cnt;
int sb[maxn];
std::vector<int>fk[maxn],kf[maxn];
int main(){
int N;scanf("%d",&N);
for(int i=1;i<=N;++i)
scanf("%d",&A[i]),++CNT[A[i]];
vis[1]=true;mu[1]=1;
for(int i=2;i<maxn;++i){
if(!vis[i])mu[pri[++cnt]=i]=-1;
for(int j=1;j<=cnt;++j){
int k=i*pri[j];
if(k>=maxn)break;
vis[k]=true;
if(i%pri[j]==0)break;
mu[k]=mu[i]*mu[pri[j]];
}
}
for(int i=1;i<=cnt;++i){
for(int j=(maxn-1)/pri[i];j>=1;--j){
CNT[j]+=CNT[j*pri[i]];
}
}
for(int i=1;i<maxn;++i)
for(int j=i;j<maxn;j+=i)
fk[j].push_back(i);
for(int i=1;i<maxn;++i){
for(auto j:fk[i])if(j>1&&j<i){
int az=0;
for(auto k:fk[i/j]){
az+=mu[k]*CNT[j*k];
}
if(az)kf[i].push_back(j);
}
}
for(int i=2;i<maxn;++i){
for(auto j:kf[i]){
int o=sg[j];
o^=(CNT[j]-CNT[i]-1)&1;
sb[o]=true;
}
while(sb[sg[i]])++sg[i];
for(auto j:fk[i]){
int o=sg[j];
o^=(CNT[j]-CNT[i]-1)&1;
sb[o]=false;
}
}
for(int i=1;i<=N;++i){
int o=sg[A[i]];
o^=((CNT[A[i]]-1)&1);
puts(o?"Aoki":"Takahashi");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现