題解 CF1375F Integer Game(構造,博弈)
阿新 • • 發佈:2020-07-05
嘗試通過構造,讓先手贏。
考慮什麼情況下,後手不得不讓兩個堆數量相等。假設某個局面下,三堆裡分別有\(a,b,c\)個石頭,不妨設\(a>b>c\)。那麼如果上一輪的操作物件是\(a\)(這一輪不能對\(a\)操作),且\(a-b=b-c\)。那麼此時,如果先手報:\(a-b\),後手就不得不讓兩堆數量相等:他要麼把\(b\)變成\(a\),要麼把\(c\)變成\(b\)。
總結一下這個條件,就是讓上一次的操作物件,變成當前最大的數,且當前三個數從大到小依次差相等。那麼此時,只需要一次操作,先手就贏了。如圖:
我們進一步思考,如何達到上述的局面呢?還是假設\(a>b>c\)
由此可知,只要上一次的操作物件是當前最大的數,先手就一定能用兩次操作獲勝。
這個條件比第一個條件弱很多,這個局面也很好達到。一開始的時候,不妨還是設\(a>b>c\),先報\(a-b\)。此時,\(a-b\)要麼被作用於\(a\)上(達到效果,使上一次操作物件是當前最大的數),要麼被作用於\(c\)
綜上所述,我們選先手,在\(4\)步以內,必能獲勝。
參考程式碼:
//problem:F #include <bits/stdc++.h> using namespace std; #define pb push_back #define mk make_pair #define lob lower_bound #define upb upper_bound #define fi first #define se second #define SZ(x) ((int)(x).size()) typedef unsigned int uint; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; ll a[4]; void work(){ //上一次的操作物件,在操作後是最大值 for(int i=1;i<=3;++i){ if(a[i]==max(a[1],max(a[2],a[3]))){ int j=1,k=2; if(i==j)j=3; if(i==k)k=3; cout<<(a[i]-a[j])+(a[i]-a[k])<<endl; int l; cin>>l; assert(l!=i); if(l==0)return; if(l==k)swap(j,k); //l=j a[j]+=(a[i]-a[j])+(a[i]-a[k]); cout<<a[i]-a[k]<<endl; cin>>l; assert(l==0); return; } } } int main() { cin>>a[1]>>a[2]>>a[3]; cout<<"First"<<endl; for(int i=1;i<=3;++i){ if(a[i]==max(a[1],max(a[2],a[3]))){ int j=1; if(i==1)j=2; cout<<a[i]-a[j]<<endl; int k; cin>>k; a[k]+=a[i]-a[j]; assert(k!=j); if(k==0)return 0; else if(k==i)work(); else{ if(a[k]>a[i])work(); else{ cout<<a[i]-a[j]<<endl; int l; cin>>l; a[l]+=a[i]-a[j]; assert(l!=k); assert(l!=j); if(l==0)return 0; else work(); } } return 0; } } return 0; }