HDU 6869 - Slime and Stones (威佐夫博弈)
題意
有兩堆石子,數量分別為\(a,b\),兩人輪流取,每次必須取一個及以上的石子
每次可以任選一堆取(個數不限),也可以兩堆都取(取的個數差值必須\(\leq k\))
兩人都以最優策略取石子,問是否存在一種情況使得先手必勝,是則輸出\(1\),否則輸出\(0\)
限制
\(1\leq T\leq 10^5\)
\(1\leq a,b\leq 10^8,\ 0\leq k\leq 10^8\)
賽時思路
這部分解法可能是現場賽幾乎不可能實現的寫法吧
- 下文令\((x,y)\)表示現在兩堆石子的數量,限制\(x\leq y\)
首先考慮最小資料的必敗態
根據題意可以得知,誰將某一堆石子取完,那麼他的對手就可以取完另外一堆,所以這種方式必敗
或者如果兩堆石子數量差在\(k\)之內(\(|a-b|\leq k\)),那麼就可以直接拿走兩堆內所有石子並獲勝
所以可以得到,如果較少的堆內剩餘\(1\)粒石子,較多的堆內剩餘\(k+2\)粒,那麼當前不論怎麼操作都會輸掉這場比賽
得到:\((1,k+2)\)為最小資料下的必敗態
為了找到規律,我們列舉兩堆石子中較少堆的數量
當較少的堆中僅存在\(1\)粒石子時——
當剩餘情況為\((1,i),\ 1\leq i\leq k+1\)時,當前操作的人可以直接拿完兩堆,所以必勝
當剩餘情況為\((1,k+2)\)
當剩餘情況為\((1,i),\ i\geq k+3\)時,當前操作的人可以將其轉換到\((1,k+2)\)的情況,所以必勝
相同的,當較少的堆中僅存在\(2\)粒石子時——(這裡不適用於\(k=0\)的情況)
當剩餘情況為\((2,i),\ 2\leq i\leq k+2\)時,當前操作的人可以直接拿完兩堆,所以必勝
當剩餘情況為\((2,i),\ k+3\leq i\leq 2k+3\),將較少的堆拿去\(1\)粒,較大的堆最多可以拿\(k+1\)粒,所以可以轉移到\((1,k+2)\)的狀態,所以必勝
當剩餘情況為\((2,2k+4)\)時,必敗
當剩餘情況為\((2,i),\ i\geq 2k+5\)
直到較少的堆記憶體在\(k+2\)粒石子時,情況發生了變化——
當剩餘情況為\((k+2,i),\ k+2\leq i\leq 2k+3\)時,當前操作的人可以直接拿完兩堆,必勝
當剩餘情況為\((k+2,i),\ i\geq 2k+4\)時,發現前面有個必敗態為\((1,k+2)\),他們共享\(k+2\)這個狀態,所以可以從\((k+2,2k+4)\)直接轉換到\((1,k+2)\)的狀態,所以該情況下必勝
綜上,可以得到的一個規律就是
後面的一個必敗態總是可以由前一個必敗態推導而來
假設\((x,y)\)是一個必敗態,假設較小的堆被拿了\(1\)粒石子,那麼較大的堆最多能拿\(k+1\)粒石子
顯然,\((x+1,y+k+2)\)無法僅通過一步就推到\((x,y)\),可能必敗
還要考慮一點,就是\(x+1\)沒有在前面的任意必敗態中出現過,否則可以直接一步轉移到更前面的必敗態,使得該點必勝
如果\(x+1\)並未出現在前面任意一個必敗態中,就可以肯定\((x+1,y+k+2)\)無法轉移到任意一個必敗態,則它不是必勝態,是一個必敗態
以\(k=1\)的情況為例,最小必敗態為\((1,3)\)
考慮\((x+1,y+k+2)\)的轉移方式,顯然\(x+1=2\)並未出現在前面任意一個必敗態中
所以\((2,6)\)是一個必敗態
繼續考慮,發現下一個狀態為\((3,9)\)
但是\(3\)存在於必敗態\((1,3)\)內,說明\((3,9)\)可以直接轉換到\((1.3)\),這是個必勝態
為了讓其不能一遍轉移得到,則可以假設兩堆都多取了一粒石子,即考慮\((x+1+1,y+k+2+1)\)
發現\(2+1+1=4\)並未出現,所以\((4,10)\)是一個必敗態
一直這樣考慮下去,粗略得到\(k=1\)的必敗態分佈情況為
\[(1,3)\\(2,6)\\(4,10)\\(5,13)\\(7,17)\\ (8,20)\\(9,23)\\(11,27)\\(12,30)\\(14,34)\\ (15,37)\\(16,40)\\(18,44)\\(19,47)\\(21,51)\\ (22,54)\\(24,58)\\(25,61)\\(26,64) \]
觀察這個分佈,得到一個規律:
\((a,b)\)的\(b-a\)值以\(2,4,6,8,10,12,14,16,18,20,\dots\)遞增
這可能是一個入手點,那麼我們把\(k=0\)的表打出來試試
當\(k=0\)時,最小資料必敗態為\((1,2)\)
按規律打表如下
\[(1,2)\\(3,5)\\(4,7)\\(6,10)\\(8,13)\\ (9,15)\\(11,18)\\(12,20)\\(14,23)\\(16,26)\\ (17,28)\\(19,31)\\(21,34)\\(22,36)\\(24,39)\\ (25,41)\\(27,44) \]
得到\(b-a\)的值以\(1,2,3,4,5,6,7,\dots\)遞增
可以得到,\(b-a\)的值是一個首項為\(k+1\),公差為\(k+1\)的等差數列
所以我們可以根據\(\frac {b-a}{k+1}\)來確定某個狀態在必敗態中的項數
如果你想問為什麼要求出項數,看下面……
實際上打出表就能發現
必敗態的\(b\)數值分佈存在一個規律(\(b_i-b_{i-1}\in\{k+2,k+3\}\))
假如這個\(\{b\}\)數列存在著通項公式,那麼肯定是形如\(b_i=\lfloor i\times k\rfloor,\ k\in\R\)
這樣才能保證前後兩項差值固定在一個集合內(雖然這個常數\(k\)可能很難表示)
那麼我們就大膽著手於找通項公式
開啟OEIS,準備嘗試玄學求出可能的通項(這是個能根據數列前幾項或者中間幾項求出通項公式的工具)
但不同的\(k\)肯定對應著不同的通項公式,所以我們再把\(k=2,3,4\)的表稍微打出前幾項
當\(k=2\)時,必敗態為
\[(1,4)\\(2,8)\\(3,12)\\(5,17)\\(6,21)\\ (7,25)\\(9,30)\\(10,34)\\(11,38)\\(13,43)\\ (14,47)\\(15,51)\\(16,55) \]
當\(k=3\)時,必敗態為
\[(1,5)\\(2,10)\\(3,15)\\(4,20)\\(6,26)\\ (7,31)\\(8,36)\\(9,41)\\(11,47)\\(12,52)\\ (13,57)\\(14,62) \]
當\(k=4\)時,必敗態為
\[(1,6)\\(2,12)\\(3,18)\\(4,24)\\(5,30)\\ (7,37)\\(8,43)\\(9,49)\\(10,55)\\(11,61)\\ (13,68)\\(14,74)\\(15,80) \]
於是我們得到了五個數列\(\{b\}\),如下
\[\{b\}= \left \{ \begin{aligned} 2,5,7,10,13,15,18,20,23,26,28,31,34,\dots (k=0)\\ 3,6,10,13,17,20,23,27,30,34,37,40,44,\dots (k=1)\\ 4,8,12,17,21,25,30,34,38,43,47,51,55,\dots (k=2)\\ 5,10,15,20,26,31,36,41,47,52,57,62,\dots (k=3)\\ 6,12,18,24,30,37,43,49,55,61,68,74,\dots (k=4) \end{aligned} \right . \]
根據OEIS的輸出,得出(需要稍微轉化一下)
\[\{b\}= \left \{ \begin{aligned} \lfloor n\times \frac{3+\sqrt 5}{2} \rfloor,\ k=0\\ \lfloor n\times \frac{4+\sqrt 8}{2} \rfloor,\ k=1\\ \lfloor n\times \frac{5+\sqrt {13}}{2} \rfloor,\ k=2\\ \lfloor n\times \frac{6+\sqrt {20}}{2} \rfloor,\ k=3\\ \lfloor n\times \frac{7+\sqrt {29}}{2} \rfloor,\ k=4\\ \end{aligned} \right . \]
容易發現規律,並得到通項表達如下
\[b_k=\lfloor n\times \frac{x+\sqrt y}{2} \rfloor\\ x=k+3\\ y=5+\frac{3+(k\times 2+1)}{2}\times k \]
(\(y\)為\({5,8,13,20,29,\dots}\),每項差\(3,5,7,9,\dots\),可以拆成\(5+\)等差數列求和)
程式
(78ms/1000ms)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
ll a,b,k;
scanf("%lld%lld%lld",&a,&b,&k);
if(a>b)
swap(a,b);
if((b-a)%(k+1)==0)
{
int id=(b-a)/(k+1);
ll x=3+k,y=(3+k*2+1)*k/2+5;
ll tmp=(x+sqrt(y))*id/2.0;
if(tmp==b)
puts("0");
else
puts("1");
}
else
puts("1");
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
solve();
return 0;
}
/*
10
15 37 1
26 64 1
21 51 1
9 23 1
25 41 0
27 44 0
14 62 3
20 105 4
19 99 4
8 36 3
*/
原版博弈
本題是威佐夫博弈(Wythoff's game)的變種
原版威佐夫博弈正是本題\(k=0\)時的情況
結論是:
假設兩堆石子數量為\((x,y),\ x\lt y\)
先手必敗,當且僅當滿足\(\frac{\sqrt 5+1}{2}(y-x)=x\)
(但我不會,還沒學)
所以想學的可以去別的地方學學
最後如果以通項方式解決,通項應該也是上面推出的那個
據說還有更簡單的遞推方法
我直接問號為敬?????