1. 程式人生 > >bzoj2281 [Sdoi2011]黑白棋

bzoj2281 [Sdoi2011]黑白棋

blog output efi 。。 ret 可以轉化 新的遊戲 gist put

Description

小A和小B又想到了一個新的遊戲。 這個遊戲是在一個1*n的棋盤上進行的,棋盤上有k個棋子,一半是黑色,一半是白色。 最左邊是白色棋子,最右邊是黑色棋子,相鄰的棋子顏色不同。 小A可以移動白色棋子,小B可以移動黑色的棋子,他們每次操作可以移動1到d個棋子。 每當移動某一個棋子時,這個棋子不能跨越兩邊的棋子,當然也不可以出界。當誰不可以操作時,誰就失敗了。 小A和小B輪流操作,現在小A先移動,有多少種初始棋子的布局會使他勝利呢?

Input

共一行,三個數,n,k,d。

Output

輸出小A勝利的方案總數。答案對1000000007取模。

Sample Input

10 4 2

Sample Output

182

HINT

1<=d<=k<=n<=10000, k為偶數,k<=100。

正解:博弈論+$dp$。

推薦博客:$nim$遊戲及其變形

首先題目似乎漏了一句話,就是白棋不能右移,黑棋不能左移。。

因為每對黑白棋相鄰,所以實際上我們可以轉化一下模型,每對黑白棋就是一堆石子,它們的距離$-1$就是石子個數。

現在每次可以取$d$個石子堆中的石子,問先手必勝的方案有多少?

這是一個經典的$nim-k$問題,結論是對於石子堆的每一個二進制位,如果這一位上為$1$的石子堆數是$d+1$的倍數,那麽先手必敗。

所以我們可以直接考慮先手必敗的方案數,再用總方案數減去即可。

設$f[i][j]$表示考慮到二進制從小到大的第$i$位,當前石子總數為$j$,先手必敗的方案數。

那麽$f[i+1][j+p*(d+1)*2^{i}]+=f[i][j]*\binom{k/2}{p*(d+1)}$,註意第二維必須$\leq n-k$。

最後我們枚舉石子數$i$,那麽$Ans-=f[15][i]*\binom{n-k/2-i}{k/2}$,這裏可以看成在合法位置中選擇$k/2$個位置的方案數。

 1 #include <bits/stdc++.h>
 2 #define il inline
 3
#define RG register 4 #define ll long long 5 #define rhl (1000000007) 6 7 using namespace std; 8 9 int c[10005][105],f[16][10005],n,k,d,ans; 10 11 il int gi(){ 12 RG int x=0,q=1; RG char ch=getchar(); 13 while ((ch<0 || ch>9) && ch!=-) ch=getchar(); 14 if (ch==-) q=-1,ch=getchar(); 15 while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar(); 16 return q*x; 17 } 18 19 il int C(RG int n,RG int m){ 20 return n<m ? 0 : c[n][min(m,n-m)]; 21 } 22 23 int main(){ 24 #ifndef ONLINE_JUDGE 25 freopen("chess.in","r",stdin); 26 freopen("chess.out","w",stdout); 27 #endif 28 n=gi(),k=gi(),d=gi(),c[0][0]=1; 29 for (RG int i=1;i<=n;++i){ 30 c[i][0]=1; 31 for (RG int j=1;j<=k && j<=i;++j){ 32 c[i][j]=c[i-1][j-1]+c[i-1][j]; 33 if (c[i][j]>=rhl) c[i][j]-=rhl; 34 } 35 } 36 f[0][0]=1,ans=C(n,k); 37 for (RG int i=0;i<15;++i) 38 for (RG int j=0;j<=n-k;++j) 39 for (RG int p=0,q;p*(d+1)<=(k>>1);++p){ 40 q=j+p*(d+1)*(1<<i); if (q>n-k) break; 41 f[i+1][q]=(1LL*f[i][j]*C(k/2,p*(d+1))+f[i+1][q])%rhl; 42 } 43 for (RG int i=0;i<=n-k;++i){ 44 ans=(-1LL*f[15][i]*C(n-k/2-i,k/2)+ans)%rhl; 45 if (ans<0) ans+=rhl; 46 } 47 cout<<ans; return 0; 48 }

bzoj2281 [Sdoi2011]黑白棋