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;
}
posted @ 2025-07-10 08:57  特别之处  阅读(59)  评论(0)    收藏  举报