1. 程式人生 > >[SDOI 2011]黑白棋

[SDOI 2011]黑白棋

print mar pro 移動 clu 顏色不同 time markdown ble

Description

題庫鏈接

給出一個 \(1\times n\) 的棋盤,棋盤上有 \(k\) 個棋子,一半是黑色,一半是白色。最左邊是白色棋子,最右邊是黑色棋子,相鄰的棋子顏色不同。
\(A\) 可以移動白色棋子,小 \(B\) 可以移動黑色的棋子,他們每次操作可以移動 \(1\sim d\) 個棋子。
每當移動某一個棋子時,這個棋子不能跨越兩邊的棋子,當然也不可以出界。當誰不可以操作時,誰就失敗了。
\(A\) 和小 \(B\) 輪流操作,現在小 \(A\) 先移動,問有多少種初始棋子的布局使他勝利。

\(1\leq n\leq 10000,1\leq k\leq 100\)

Solution

是一道假題...參考了 黃學長的做法 ... 具體可以參見他的博客。

Code

#include <bits/stdc++.h>
using namespace std;
const int yzh = 1000000007, N = 10000;

int n, k, d, a[N+5], b[N+5], bin[20], f[16][N+5];

int C(int n, int m) {return 1ll*a[n]*b[m]%yzh*b[n-m]%yzh; }
void work() {
    scanf("%d%d%d", &n, &k, &d);
    a[0
] = b[0] = a[1] = b[1] = bin[0] = 1; for (int i = 2; i <= n; i++) b[i] = -1ll*yzh/i*b[yzh%i]%yzh; for (int i = 2; i <= n; i++) a[i] = 1ll*i*a[i-1]%yzh, b[i] = 1ll*b[i]*b[i-1]%yzh; for (int i = 1; i < 20; i++) bin[i] = (bin[i-1]<<1); f[0][0] = 1; for (int i = 0; i < 15; i++) for
(int j = 0; j <= n-k; j++) for (int p = 0; p*(d+1) <= k/2 && p*(d+1)*bin[i]+j <= n-k; p++) (f[i+1][p*(d+1)*bin[i]+j] += 1ll*f[i][j]*C(k/2, p*(d+1))%yzh) %= yzh; int ans = C(n, k); for (int i = 0; i <= n-k; i++) (ans -= 1ll*f[15][i]*C(n-k/2-i, k/2)%yzh) %= yzh; printf("%d\n", (ans+yzh)%yzh); } int main() {work(); return 0; }

[SDOI 2011]黑白棋