移動金幣 SDOI2019

2022-05-27 11:21:19 字數 1877 閱讀 9300

乙個 \(1\times n\) 的棋盤上最初擺放有 \(m\) 枚金幣。其中每一枚金幣佔據了乙個獨立的格仔,任意乙個格仔內最多只有一枚金幣。

alice 和 bob 將要進行如下的一場遊戲。二人輪流操作,且 alice 先行。當輪到乙個玩家的時候,他可以選擇一枚金幣,並將其向左移動任意多格,且至少移動一格。金幣不能被移出棋盤,也不能越過其它金幣。

如果輪到乙個玩家的時候他已經無法做出任何有效操作了(顯然這個時候 \(m\) 枚金幣恰好落在最左側的 \(m\) 個格仔中),則被判定為輸家。已經知道 alice 和 bob 都是極致聰明的人,他們在任何局面下總能做出最優的操作。那麼有多少初始狀態能保證 alice 必勝呢?

輸入僅有一行幷包含兩個正整數,依次為 \(n\) 和 \(m\) ,如題目所述。

輸出乙個整數,表示有多少初始狀態可以保證 alice 作為先手方能先手必勝。由於答案可能很大,請輸出關於 \(10^9+9\) 取模後的值。

首先不難發現,把金幣向左移改成向右移是沒有區別的

然後把題目看作是\(m\)枚金幣把\(n-m\)個空位分成了\(m+1\)個部分(編號從\(0\sim m\)),那麼每次把第\(i\)枚硬幣向右移動就相當於是把若干個空位從第\(i\)部分移動到了第\(i-1\)部分

然後這顯然是乙個階梯\(nim\)模型,即每次可以選擇乙個\(i\neq 0\),將若干個物品從第\(i\)堆移到第\(i-1\)堆

我們其實不用管\(m\)枚金幣具體在哪些位置,所以我們現在需要解決的問題是:將\(n-m\)個物品分成編號從\(0\sim m\)的\(m+1\)堆,要求所有奇數堆的異或和不為\(0\),有多少種方案?

容斥一下,可以用總方案數減去奇數堆異或和為\(0\)的方案數

設\(dp[i][j]\)表示所有奇數堆的二進位制前\(i\)位的異或和為0,共用了\(j\)個物品的方案數

在二進位制的每一位上,為了異或和為\(0\),必須要放偶數個\(1\)

假設\(m+1\)堆中有\(a\)個奇數堆,\(b\)個偶數堆,

那麼轉移方程為:\(dp[i][j]=\sum\limits_ dp[i-1][j-k*2^] * c(a, k)\)

表示在第\(i\)位上放\(k\)個1,所以在\(a\)個奇數字上任選\(k\)個放上1

然後填好所有奇數堆後,剩下的沒有用到的物品就可以用插板法隨意地分到偶數堆裡

時間複雜度\(o(nm\log n)\),但是實際上跑得很快

#include using namespace std;

typedef long long ll;

templateinline void read(t &num)

const ll mod = 1000000009;

ll fac[150005], invf[150005], dp[21][150005], ans; // 放了二進位制前i位 用了j個物品

int n, m, l;

inline ll fpow(ll x, ll t)

inline ll c(ll _n, ll _m)

void init()

invf[150000] = fpow(fac[150000], mod-2);

for (int i = 149999; i; i--)

}int main()

int a = (m + 1) / 2, b = (m + 2) / 2;

dp[0][0] = 1;

for (int i = 0; i < l; i++)

} }for (int i = 0; i <= n; i++)

ans = (c(n+m, m) - ans + mod) % mod;

printf("%lld\n", ans);

return 0;

}

SDOI 2019 移動金幣 題解

題目傳送門 題目大意 乙個長度為 n nn 的序列上有 m mm 個金幣,兩個人輪流操作,乙個人可以將乙個金幣向左移動任意格,但是不能越過別的金幣,問有多少種局面先手必勝。感覺像這兩題 1,2 的合體,不過合的也很巧妙。轉化一下這個博弈 相當於有 m 1 m 1m 1 堆石子,每次可以將一堆石子中的...

SDOI2019移動金幣 博弈論

題意簡述 在乙個 1 n 的棋盤上,有 m 個棋子.小 a 小 b 每次可以把乙個棋子向左移動若干格,但不能越過其他棋子.第乙個無法操作的人輸.問給定 n,m 有多少種局面使得 小a 必勝 n leq 150000,m leq 50 sdoi2019 移動金幣 includeusing namesp...

SDOI 2019 快速查詢

傳送門 day1 t1 給定乙個長度為 n nn 的整數數列 有 q qq 次操作,操作有 6 66 種,分別為 單點賦值,全域性加,全域性乘,全域性賦值,單點查值,全域性求和。操作的讀入有點鬼畜啊,建議仔細讀一下。資料範圍 1 n 109 1 n 10 9 1 n 10 9,1 q 10 71 l...