AtCoder 2305 [AGC010D] Decrementing(博弈)
problem
Luogu鏈接
solution
case1:aaa 中如果有 111 的存在,那么相當于第二步失效,最后的結果僅由 ∑ai?1\sum a_i-1∑ai??1 的奇偶性決定(奇數先手贏,偶數后手贏)
奇數先手贏,偶數后手贏。
case2:如果 ∑ai?1\sum a_i-1∑ai??1 為奇數,先手必勝。
這看起來就似乎是正確的。
首先因為偶數除以奇數還是偶數,奇數除以奇數還是奇數,所以如果 gcd?\gcdgcd 是奇數,對奇偶性不影響。
如果先手能維持這個奇偶性到最后,即保證每人每次只有第一步操作有效,那他就贏了。
先手只需任選一個偶數 ?1-1?1,再算上初始局面必然包含的一個奇數(否則初始 gcd?\gcdgcd 不為 111),這樣至少就有兩個奇數。
- 此時若序列長度 >2>2>2,先手 ?1-1?1 之后:
- gcd?=1\gcd=1gcd=1。后手再讓任意一個數 ?1-1?1,序列的 gcd?\gcdgcd 仍然為 111,后手的第二步等價于無效。
- gcd?≠1\gcd\ne 1gcd?=1,但 gcd?\gcdgcd 也一定是奇數。除掉 gcd?\gcdgcd 后,出現 111,奇偶性未改變。后手仍然面臨的奇偶性為偶。先手必勝。
- 特殊情況是序列長度 =2=2=2,先手 ?1-1?1 之后:
- 可能兩數相等,那正好就直接贏了。
- 要是不相等,并且 ?1-1?1 之后出現了倍數關系,那沒什么影響,顯然一個是另一個的奇數倍。約去 gcd?\gcdgcd 后就是一個 111 加上一個奇數,后手面臨的奇偶性仍然為偶,先手仍然獲勝。
要想保證每人每次只能取一個也很簡單,先手只需任選一個偶數減1,再算上初始局面必然包含的一個奇數(否則初始gcd不為1),這樣就至少有兩個奇數了。
case3:如果 ∑i=1nai?1\sum_{i=1}^na_i-1∑i=1n?ai??1 為偶數,且有 >1>1>1 個 aia_iai? 為奇數,則先手必敗。
若有多個奇數,這一輪先手選擇一個變為偶數,gcd?\gcdgcd 仍然只可能是奇數,下一輪后手就能將其重新變回偶數,使先手第二步無效。
case4:如果為偶數,先手肯定想要翻盤,唯一辦法是 2∣gcd?2\mid \gcd2∣gcd。
如果 ∑i=1nai?1\sum_{i=1}^na_i-1∑i=1n?ai??1 為偶數,且只有一個奇數,先手一定操作這個奇數,那么這一輪至少能 /2/2/2,這是唯一的翻盤機會。
考慮做完上述特判和操作后,將操作權遞交給對手。
只有 case4 是需要模擬操作下去的 O(nlog?2w)O(n\log^2w)O(nlog2w),其余三種情況一步判斷輸贏即可。
#include <bits/stdc++.h> using namespace std; #define maxn 100005 #define int long long int n; int a[maxn];int gcd( int x, int y ) {if( ! y ) return x;else return gcd( y, x % y ); }signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );bool op = 0;while( 1 ) {int cnt = 0, sum = 0, flag = 0;for( int i = 1;i <= n;i ++ )cnt += (a[i] & 1), sum += a[i] - 1, flag |= (a[i] == 1);if( sum & 1 ) break;if( cnt ^ 1 ) { op ^= 1; break; }if( flag ) { op ^= 1; break; }int d = 0;for( int i = 1;i <= n;i ++ ) {if( a[i] & 1 ) a[i] --;d = gcd( d, a[i] );}for( int i = 1;i <= n;i ++ ) a[i] /= d;op ^= 1;}if( ! op ) puts("First");else puts("Second");return 0; }總結
以上是生活随笔為你收集整理的AtCoder 2305 [AGC010D] Decrementing(博弈)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 修改病句大方法修改病句大方法的例子
- 下一篇: 一般图带权多重匹配(欧拉图+最小费用流)