题解 P4706【取石子】
题意
有 堆棋子,第 堆有 个棋子,定义一次操作为选择第 堆棋子中任意个棋子转移到第 堆中。其中 是 的质因数。
两人轮流操作,不能操作者输。若先手第一步随机操作一步,问先手获胜的概率。对 取模。
。
思路
前置知识:阶梯 博弈
描述:有 堆棋子,第 堆有 个棋子,定义一次操作为选择第 堆棋子中任意个棋子转移到第 堆中。两人轮流操作,不能操作者输。求先手是否有必胜策略。
可以得到,此时的 函数 ,此处不多作介绍,可以参考这份讲解。
设 的标准分解式为 ,定义 。这个可以线性筛出来。
我们发现,如果以 的奇偶性分层连边,则问题转化为在奇偶层之间移动棋子的阶梯 博弈。
首先我们知道先手第一步走的方式有 种。
然后来判断有多少种合法方法。
枚举奇层的所有 ,若操作后 变为 ,则先手能胜利,则定义 ,则 变为 后 变为 。
然后对于 和 的大小分类讨论。
- ,此时 ,若对 做出改动,则 定不等于 ,故此类无贡献;
- ,考虑将 处的 颗棋子转移至偶层,则对答案作出 的贡献;
- ,考虑枚举 ,将偶层 处的 颗棋子转移至奇层 处,则对答案作出 的贡献。
最后除一下得出概率就行了!
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=1e6+10,mod=998244353;
int n,a[N],rnd,sol;
bitset<N>p;
int pri[N],cnt,sum[N];
bool odd[N];
/*
sum->质因数个数
odd->指数和是否为奇
*/
inline int qpow(int x,int y){
int res=1;
while(y){
if(y&1) res=1ll*res*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return res;
}
inline void sieve(int n){
p[1]=1;
for(int i=2;i<=n;i++){
if(!p[i]){
pri[++cnt]=i;
sum[i]=odd[i]=1;
}
for(int j=1;j<=cnt&&i*pri[j]<=n;j++){
p[i*pri[j]]=1;
odd[i*pri[j]]=odd[i]^1;
if(i%pri[j]==0) { sum[i*pri[j]]=sum[i]; break; }
sum[i*pri[j]]=sum[i]+1;
}
}
}
int SG;
int main(){
n=read();
sieve(n);
for(int i=1;i<=n;i++){
a[i]=read();
if(odd[i]) SG^=a[i];
rnd=(rnd+1ll*a[i]*sum[i])%mod;
}
for(int i=1;i<=n;i++){
if(odd[i]){
int need=SG^a[i];
if(need==a[i]) continue;
if(need<a[i]) sol=(sol+sum[i])%mod;
else{
for(int j=1;j<=cnt&&pri[j]*i<=n;j++){
if(a[i*pri[j]]>=need-a[i]) sol++;
}
sol-=sol>=mod?mod:0;
}
}
}
write(1ll*sol*qpow(rnd,mod-2)%mod);
flush();
}
再见 qwq~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】