[SDOI2011]黑白棋 题解

题目链接https://www.luogu.com.cn/problem/P2490

题意略

题解:

首现发现对于一次单独的游戏,是一个取石子游戏:

共有 \(\frac{k}{2}\) 堆石子,每次取至多 \(d\) 堆,每堆若干个,是个 \(\text{k-nim}\) 游戏。

结论:将每堆石子的个数用二进制表示。如果过每一位 \(1\) 的个数都能被 \(d+1\) 整除后手必胜,否则先手必胜。

感性证明一下:

  • 对于没有石子了,显然成立。

  • 对于一个先手必胜态是能转换成一个后手必胜态的:对于每一位都考虑,必有一些位上不能被 \(d+1\) 整除,对这些位操作即可。

  • 对于一个后手必败态:如果想要操作成后手必败态需要将至少一位操作 \(d+1\) 次,这显然不行。

于是考虑如何计数,可以考虑 \(\binom{n}{k}\) 减去不合法方案数。

不合法方案数很好 DP ,对每一位考虑,满足是 \(d+1\) 的倍数,挺显然的。

注意 DP 时的边界。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=10005,M=105,L=15,mod=1e9+7;
int n,k,d,ans,c[N][M],f[L][N];
signed main(){
	scanf("%d%d%d",&n,&k,&d);
	f[0][0]=c[0][0]=1;
	for(int i=1;i<=n;i++){
		c[i][0]=1;
		for(int j=1;j<=k;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
	}
	for(int i=0;i+1<L;i++)
		for(int j=0;j<=n-k;j++)
			for(int x=0;j+k+(x<<i)<=n&&x<=k/2;x+=d+1) (f[i+1][j+(x<<i)]+=1ll*f[i][j]*c[k/2][x]%mod)%=mod;
	for(int i=0;i<=n-k;i++) (ans+=1ll*f[L-1][i]*c[n-i-k/2][k/2]%mod)%=mod;
	printf("%d\n",(c[n][k]-ans+mod)%mod);
	return 0;
}
posted @ 2021-03-09 23:01  shrtcl  阅读(84)  评论(0编辑  收藏  举报