【uoj#51】[UR #4]元旦三俠的遊戲 博弈論+dp
阿新 • • 發佈:2018-01-08
sof mic pro 表示 urn 遊戲 spa 方法 div
題目描述
給出 $n$ 和 $m$ ,$m$ 次詢問。每次詢問給出 $a$ 和 $b$ ,兩人輪流選擇:將 $a$ 加一或者將 $b$ 加一,但必須保證 $a^b\le n$ ,無法操作者輸,問先手是否必勝。
$n\le 10^9$ ,$m\le 10^5$ ,$a\ge 2$ ,$b\ge 1$ ,$a^b\le n$
題解
博弈論+dp
顯然可以想到預處理 $f[i][j]$ 表示 $a$ 為 $i$ ,$b$ 為 $j$ 時先手能否勝利。顯然由 $f[i+1][j]$ 和 $f[i][j+1]$ 推出。
但是由於 $n$ 有 $10^9$ 就會GG...
我們考慮:當 $i^j\le n$ 且 $i^{j+1}>n$ 時,先手只能選擇將 $a$ 加一,後手也一樣。因此勝負已定。
因此當 $b=1$ 時可以只預處理到 $f[\sqrt n][1]$ ,當 $a>\sqrt n$ 時顯然可以 $O(1)$ 判斷。
時間復雜度 $O(m+\sqrt n\log n)$ 。
其實對於每一個 $b$ 都可以用同樣的方法判斷,時間復雜度變為 $O(m+\sum\limits_{i=2}^{\log n}\sqrt[i]{n})=O(m+\sqrt n)$ 但沒什麽必要。。。
#include <cstdio> int p[32010][31] , log[32010] , f[32010][31]; //0: win int main() { int n , m , i , j , a , b; scanf("%d%d" , &n , &m); for(i = 2 ; i <= 32000 ; i ++ ) { if(i > n) log[i] = 0; else { p[i][1] = i; for(j = 2 ; 1ll * p[i][j - 1] * i <= n ; j ++ ) p[i][j] = p[i][j - 1] * i; log[i] = j - 1; } } f[32001][1] = !((n - 32001) & 1); for(i = 32000 ; i != 1 ; i -- ) for(j = log[i] ; j ; j -- ) f[i][j] = !(f[i][j + 1] || f[i + 1][j]); while(m -- ) { scanf("%d%d" , &a , &b); puts((a > 32000 ? !((n - a) & 1) : f[a][b]) ? "No" : "Yes"); } return 0; }
【uoj#51】[UR #4]元旦三俠的遊戲 博弈論+dp