对弈(nim-k游戏博弈)
problem
AliceAliceAlice 和 BobBobBob 又在玩游戲。
AliceAliceAlice 和 BobBobBob 在一個 1×n1\times n1×n 的網格圖上玩游戲,網格圖的 nnn 個格子中,有 kkk 個格子內被各放了一個棋子,其中 kkk 是一個偶數。
從左到右,這 kkk 個棋子依次被染色為紅色、藍色、紅色、……、藍色、紅色、藍色。其中紅棋子是 AliceAliceAlice 的,藍棋子是 BobBobBob 的。
兩人輪流操作,需要遵循以下規則:
-
每一回合輪到某人操作時,這個人只能移動自己的棋子。
-
每個棋子只能在網格圖內的格子之間移動,并且在移動棋子的時候,每個棋子不能跨過和這個棋子相鄰的其它棋子。
-
每次最少需要移動 111 個棋子,最多可以移動 mmm 個棋子。
-
若移動多個棋子,則必須選擇多個不同的棋子分別移動,每一個被選擇移動的棋子不能停留在原位。
例如下圖,當 AliceAliceAlice 操作時,若她要移動從左到右的第三個紅棋子,那么她可以移動到的范圍有下面這三個空心棋子的位置。
若某一回合,輪到某人操作時,這個人無法操作,那么這個人就輸了。
現在 先手,假設兩人均采用最優策略。
給定 n,k,mn,k,mn,k,m,請你求出有多少符合題意的初始局面,使得 AliceAliceAlice 必勝。對 1e9+71e9+71e9+7 取模。
solution
observation:BobBobBob 只會向左移動,AliceAliceAlice 只會向右移動。
證明:因為如果 BobBobBob 向右移動,那么其左邊的 AliceAliceAlice 的格子就會跟著移動【一直擠 BobBobBob 】,相互擠對方,但左邊第一個是屬于 AliceAliceAlice 的格子,所以最后一定是 AliceAliceAlice 會擠著 BobBobBob。AliceAliceAlice 向左移動也是同理。
所以把一個 AliceAliceAlice 和一個 BobBobBob 的格子綁成一對。
記 ai:a_i:ai?: 第 iii 個紅棋的位置,bi:b_i:bi?: 第 iii 個藍棋的位置,di=bi?ai?1d_i=b_i-a_i-1di?=bi??ai??1。
這相當于有 k2\frac{k}{2}2k? 堆石子,每堆石子個數為 did_idi?。
這就轉化成了經典的 nim-k 游戲【每次可以選擇 1~k1\sim k1~k 堆石子,拿走任意的石子數量,最后不能操作者輸。】
結論:當所有的 did_idi? 轉化成二進制后,每個二進制位上為 111 的個數 %(k+1)=0\%(k+1)=0%(k+1)=0 則是必敗局面。
證明:
-
全 000 的局面一定是 PPP 局面。
-
任何一個 PPP 狀態,經過一次操作以后必然會到達 NNN 狀態。
-
在某一次移動中,至少有一堆被改變,即至少有一個二進制位被改變。
由于最多只能改變 kkk 堆石子,所以對于任何一個二進制位,111 的個數至多改變 kkk。
又有原先總數為 k+1k+1k+1 的整數倍,所以改變之后必然不可能仍是 k+1k+1k+1 的整數倍。
故在 PPP 狀態下一次操作的結果必然是 NNN 狀態。
-
-
任何 NNN 狀態,總有一種操作使其變化成 PPP 狀態。
-
從高位到低位考慮所有的二進制位。
假設用了某種方法,改變了 mmm 堆,使 iii 位之前的所有位都變為 k+1k+1k+1 的整數倍。
現在要證明總有一種方法讓第 iii 位也恢復到 k+1k+1k+1 的整數倍(包括 000)。
顯然,對于那些已經改變的 mmm 堆,當前的第 iii 位可以自由選擇 111 或000【這只取決于操作時后拿走的石子個數】。
不考慮已經操作的 mmm 堆,記剩下的堆的第 iii 位上 111 的總和為 sumsumsum
-
分類討論:
-
sum≤k?msum\le k-msum≤k?m
此時可以將這些堆上的 111 全部拿掉,然后讓那 mmm 堆得 iii 位全部置成 000。
-
sum>k?msum>k-msum>k?m
此時我們在之前改變的 mmm 堆中選擇 k+1?sumk+1-sumk+1?sum 堆,將他們的第 iii 位設置成 111。剩下的設置成000。
由于 k+1?sum<k+1?(k?m)<m+1?k+1?sum≤mk+1-sum<k+1-(k-m)<m+1\Rightarrow k+1-sum\le mk+1?sum<k+1?(k?m)<m+1?k+1?sum≤m,的確可以做到。
-
-
-
原博客證明
這樣就可以 dpdpdp 了,用所有方案減去必敗方案。
dpi,j:dp_{i,j}:dpi,j?: 考慮到二進制位的 iii 位,一共用了 jjj 個石子的不合法方案數。
枚舉下一個二進制有多少堆石子為 111,石子堆數必須是 m+1m+1m+1 的倍數。
dpi,j→dpi+1,j+2i+1?tdp_{i,j}\rightarrow dp_{i+1,j+2^{i+1}·t}dpi,j?→dpi+1,j+2i+1?t?
當然需要考慮是哪幾堆,所以需要組合數。
最后要考慮將所有格子分成 kkk 堆,用隔板法計算。
code
#include <bits/stdc++.h> using namespace std; #define maxn 10005 #define int long long #define mod 1000000007 int fac[maxn], inv[maxn], dp[maxn]; int n, k, m;int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }void init() {fac[0] = inv[0] = 1;for( int i = 1;i <= n;i ++ ) fac[i] = fac[i - 1] * i % mod;inv[n] = qkpow( fac[n], mod - 2 );for( int i = n - 1;i;i -- ) inv[i] = inv[i + 1] * ( i + 1 ) % mod; }int C( int n, int m ) { return fac[n] * inv[m] % mod * inv[n - m] % mod; }signed main() {freopen( "chess.in", "r", stdin );freopen( "chess.out", "w", stdout );scanf( "%lld %lld %lld", &n, &k, &m );init();int ans = C( n, k );n -= k, k >>= 1;dp[0] = 1;for( int w = 0;w < 15;w ++ )for( int i = n;i;i -- )for( int j = m + 1;( 1 << w ) * j <= i and j <= k;j += m + 1 )dp[i] = ( dp[i] + dp[i - ( 1 << w ) * j] * C( k, j ) ) % mod;for( int i = 0;i <= n;i ++ )ans = ( ans - dp[i] * C( n - i + k, k ) % mod + mod ) % mod;printf( "%lld\n", ans );return 0; }總結
以上是生活随笔為你收集整理的对弈(nim-k游戏博弈)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么查自己的银行卡号 查询银行卡号的方法
- 下一篇: 【无码专区7】括号序列(思维)