CF838C Future Failure 题解
太久不写了,感觉这道题挺好的,就记下吧
首先考虑什么情况下先手必胜,我们注意到不同长度间排列个数并不相同,如果说在长度为\(n\)的情况下有偶数种排列方式,那么先手必胜,理由如下:
1.如果取掉某一个字符后进行博弈,答案是后手必胜,那么先手一定可以直接取掉这个字符达到必胜。
2.如果所有字符去掉后都是先手必胜,因为有偶数种排列方式,所以可以进行奇数次重拍,所以先手开始重拍最后一定轮到后手取掉字符,先手依然必胜。
然后再来看第二种情况,就是长度为\(n\)的情况下有奇数种排列,只有\(n\)为奇数的时候必胜,否则必败。理由如下:
先手第一步只能取数,方案数会乘上\(\frac{a_i}{n}\),考虑找到最小的\(lowbit(a_i)\)对应的\(a_i\),因为\(\sum{a_i}=n\)那么\(lowbit(a_i) \le lowbit(n)\),所以总共操作\(n\)次,当\(n\)是奇数的时候先手必胜。
那么答案就相当于计算\(n\)为偶数的时候排列为奇数的个数,注意到排列为奇数意味着每一个\(n\)的二进制位上的数都对应到了\(a_i\)上,直接跑dp就可以了,可以钦定一下每一回必须选择\(lowbit(i)\),然后假设选择了\(x\)个,答案乘上\(A^x_n\)
就可以了。代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,k,ans,modd,zhi,dp[27][250010],jie[250010],ni[250010];
int kuai(int q,int w){
zhi=1;
while(w){
if(w&1){
zhi=zhi*q%modd;
}
q=q*q%modd;
w=w>>1;
}
return zhi;
}
inline int lowbit(int q){
return q&(-q);
}
inline int dfs(int q,int w){
if(q>k){
return 0;
}
if(dp[q][w]!=-1){
return dp[q][w];
}
if(!w){
dp[q][w]=jie[n]*jie[k]%modd*ni[k-q]%modd;
return dp[q][w];
}
dp[q][w]=0;
int news=w-lowbit(w);
for(int s=news;s;s=(s-1)&news){
dp[q][w]=(dp[q][w]+ni[w-s]*dfs(q+1,s)%modd)%modd;
}
dp[q][w]=(dp[q][w]+ni[w]*dfs(q+1,0)%modd)%modd;
return dp[q][w];
}
signed main(){
cin>>n>>k>>modd;
jie[0]=ni[0]=1;
for(int i=1;i<=n;i++){
jie[i]=jie[i-1]*i%modd;
ni[i]=kuai(jie[i],modd-2);
}
ans=kuai(k,n);
if(n%2==0){
memset(dp,-1,sizeof(dp));
ans=(ans-dfs(0,n)+modd)%modd;
}
cout<<ans;
return 0;
}
浙公网安备 33010602011771号