日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

对弈(nim-k游戏博弈)

發(fā)布時(shí)間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 对弈(nim-k游戏博弈) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

problem

AliceAliceAliceBobBobBob 又在玩游戲。

AliceAliceAliceBobBobBob 在一個(gè) 1×n1\times n1×n 的網(wǎng)格圖上玩游戲,網(wǎng)格圖的 nnn 個(gè)格子中,有 kkk 個(gè)格子內(nèi)被各放了一個(gè)棋子,其中 kkk 是一個(gè)偶數(shù)。

從左到右,這 kkk 個(gè)棋子依次被染色為紅色、藍(lán)色、紅色、……、藍(lán)色、紅色、藍(lán)色。其中紅棋子是 AliceAliceAlice 的,藍(lán)棋子是 BobBobBob 的。

兩人輪流操作,需要遵循以下規(guī)則:

  • 每一回合輪到某人操作時(shí),這個(gè)人只能移動(dòng)自己的棋子。

  • 每個(gè)棋子只能在網(wǎng)格圖內(nèi)的格子之間移動(dòng),并且在移動(dòng)棋子的時(shí)候,每個(gè)棋子不能跨過和這個(gè)棋子相鄰的其它棋子。

  • 每次最少需要移動(dòng) 111 個(gè)棋子,最多可以移動(dòng) mmm 個(gè)棋子。

  • 若移動(dòng)多個(gè)棋子,則必須選擇多個(gè)不同的棋子分別移動(dòng),每一個(gè)被選擇移動(dòng)的棋子不能停留在原位。

例如下圖,當(dāng) AliceAliceAlice 操作時(shí),若她要移動(dòng)從左到右的第三個(gè)紅棋子,那么她可以移動(dòng)到的范圍有下面這三個(gè)空心棋子的位置。

若某一回合,輪到某人操作時(shí),這個(gè)人無法操作,那么這個(gè)人就輸了。

現(xiàn)在 先手,假設(shè)兩人均采用最優(yōu)策略。

給定 n,k,mn,k,mn,k,m,請(qǐng)你求出有多少符合題意的初始局面,使得 AliceAliceAlice 必勝。對(duì) 1e9+71e9+71e9+7 取模。

solution

observation:BobBobBob 只會(huì)向左移動(dòng),AliceAliceAlice 只會(huì)向右移動(dòng)。

證明:因?yàn)槿绻?BobBobBob 向右移動(dòng),那么其左邊的 AliceAliceAlice 的格子就會(huì)跟著移動(dòng)【一直擠 BobBobBob 】,相互擠對(duì)方,但左邊第一個(gè)是屬于 AliceAliceAlice 的格子,所以最后一定是 AliceAliceAlice 會(huì)擠著 BobBobBobAliceAliceAlice 向左移動(dòng)也是同理。

所以把一個(gè) AliceAliceAlice 和一個(gè) BobBobBob 的格子綁成一對(duì)。

ai:a_i:ai?:iii 個(gè)紅棋的位置,bi:b_i:bi?:iii 個(gè)藍(lán)棋的位置,di=bi?ai?1d_i=b_i-a_i-1di?=bi??ai??1

這相當(dāng)于有 k2\frac{k}{2}2k? 堆石子,每堆石子個(gè)數(shù)為 did_idi?

這就轉(zhuǎn)化成了經(jīng)典的 nim-k 游戲【每次可以選擇 1~k1\sim k1k 堆石子,拿走任意的石子數(shù)量,最后不能操作者輸。】

結(jié)論:當(dāng)所有的 did_idi? 轉(zhuǎn)化成二進(jìn)制后,每個(gè)二進(jìn)制位上為 111 的個(gè)數(shù) %(k+1)=0\%(k+1)=0%(k+1)=0 則是必?cái)【置妗?/p>

證明:

  • 000 的局面一定是 PPP 局面。

  • 任何一個(gè) PPP 狀態(tài),經(jīng)過一次操作以后必然會(huì)到達(dá) NNN 狀態(tài)。

    • 在某一次移動(dòng)中,至少有一堆被改變,即至少有一個(gè)二進(jìn)制位被改變。

      由于最多只能改變 kkk 堆石子,所以對(duì)于任何一個(gè)二進(jìn)制位,111 的個(gè)數(shù)至多改變 kkk

      又有原先總數(shù)為 k+1k+1k+1 的整數(shù)倍,所以改變之后必然不可能仍是 k+1k+1k+1 的整數(shù)倍。

      故在 PPP 狀態(tài)下一次操作的結(jié)果必然是 NNN 狀態(tài)。

  • 任何 NNN 狀態(tài),總有一種操作使其變化成 PPP 狀態(tài)。

    • 從高位到低位考慮所有的二進(jìn)制位。

      假設(shè)用了某種方法,改變了 mmm 堆,使 iii 位之前的所有位都變?yōu)?k+1k+1k+1 的整數(shù)倍。

      現(xiàn)在要證明總有一種方法讓第 iii 位也恢復(fù)到 k+1k+1k+1 的整數(shù)倍(包括 000)。

      顯然,對(duì)于那些已經(jīng)改變的 mmm 堆,當(dāng)前的第 iii 位可以自由選擇 111000【這只取決于操作時(shí)后拿走的石子個(gè)數(shù)】。

      不考慮已經(jīng)操作的 mmm 堆,記剩下的堆的第 iii 位上 111 的總和為 sumsumsum

      • 分類討論:

        • sum≤k?msum\le k-msumk?m

          此時(shí)可以將這些堆上的 111 全部拿掉,然后讓那 mmm 堆得 iii 位全部置成 000

        • sum>k?msum>k-msum>k?m

          此時(shí)我們?cè)谥案淖兊?mmm 堆中選擇 k+1?sumk+1-sumk+1?sum 堆,將他們的第 iii 位設(shè)置成 111。剩下的設(shè)置成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?summ,的確可以做到。

原博客證明

這樣就可以 dpdpdp 了,用所有方案減去必?cái)》桨浮?/p>

dpi,j:dp_{i,j}:dpi,j?: 考慮到二進(jìn)制位的 iii 位,一共用了 jjj 個(gè)石子的不合法方案數(shù)。

枚舉下一個(gè)二進(jìn)制有多少堆石子為 111,石子堆數(shù)必須是 m+1m+1m+1 的倍數(shù)。

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?

當(dāng)然需要考慮是哪幾堆,所以需要組合數(shù)。

最后要考慮將所有格子分成 kkk 堆,用隔板法計(jì)算。

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; }

總結(jié)

以上是生活随笔為你收集整理的对弈(nim-k游戏博弈)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。