luogu P2490 [SDOI2011]黑白棋
https://www.luogu.com.cn/problem/P2490
首先肯定是把相邻的黑白棋子之间的距离视为一堆棋子
然后问题就转换成了k-nim
解法是转换为二进制后
r
i
r_i
ri表示第
i
i
i为1的个数%(k+1)
如果
r
r
r全部为0那先手必败,否则先手必胜
对于这题,这题是统计方案
显然必败的情况比较好DP
设
f
[
i
]
[
j
]
表
示
前
i
位
,
用
了
j
个
石
子
必
败
的
方
案
数
f[i][j]表示前i位,用了j个石子必败的方案数
f[i][j]表示前i位,用了j个石子必败的方案数
每次枚举
(
d
+
1
)
(d+1)
(d+1)的倍数
×
2
i
\times 2^i
×2i转移即可
f
[
i
]
[
j
+
x
∗
(
d
+
1
)
∗
2
i
]
+
=
f
[
i
]
[
j
]
∗
C
k
x
∗
(
d
+
1
)
f[i][j+x*(d+1)*2^i]+=f[i][j]*C_k^{x*(d+1)}
f[i][j+x∗(d+1)∗2i]+=f[i][j]∗Ckx∗(d+1)
然后再用总方案数减去必败的即可(注意要乘个组合数)
code:
#include<bits/stdc++.h>
#define N 40005
#define mod 1000000007
using namespace std;
int c[N][205], dp[18][N], n, k, d;
int main() {
scanf("%d%d%d", &n, &k, &d);
for(int i = 0; i <= n; i ++) c[i][0] = 1;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= 200; j ++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
dp[0][0] = 1;
for(int i = 0; i <= 15; i ++)
for(int j = 0; j <= n - k; j ++) if(dp[i][j]) {
for(int x = 0; j + (1 << i) * x * (d + 1) <= n - k && x * (d + 1) <= k / 2; x ++) {
(dp[i + 1][j + (1 << i) * x * (d + 1)] += 1ll * dp[i][j] * c[k / 2][x * (d + 1)] % mod) %= mod;
}
}
long long ans = c[n][k];
for(int i = 0; i <= n - k; i ++)
ans = (ans - 1ll * dp[16][i] * c[n - i - k + k / 2][k / 2] + mod) % mod;
printf("%lld", ans);
return 0;
}