【CF】【博弈論】C. Permutation Game
阿新 • • 發佈:2021-09-16
C. Permutation Game
鋪墊
必勝態
當前玩傢俱有掌握勝局的狀態
必敗態
當前玩家無法擺脫輸局的必然狀態
在兩個人的博弈中,一個人的勝利是建立在另一個人的失敗的事實上,因而一個人若處於必勝態,那麼另一個必然處於必敗態。
題意
若一個\(a_j>a_i\),且\(|j-i|mod\space a_i==0\),當前玩家可以從i向j轉移,從而將問題丟給下一個玩家。重複操作,直到一個玩家無法再繼續轉移下去。
在這題中必敗態是必然存在的,因為最大值是無法再向其他位置轉移的,即便是沒有任何位置向最大值轉移,第二大值也是必敗態。同時任何能夠向必敗態轉移的狀態都是必勝態。
因而,我們可以在實際的處理的過程預設當前位置是必敗態,如果能轉到一個確切的必敗態,再把當前位置的狀態重新修改為必勝態。
同時用記憶化搜尋來減少不必要的搜尋量。
此外,作為博弈,每一個人都希望能夠轉移到一個對方為必敗態的情況,這樣自己就勝利了。
#include <bits/stdc++.h> #define MEM(a,x) memset(a,x,sizeof(a)) #define W(a) while(a) #define gcd(a,b) __gcd(a,b) #define pi acos(-1.0) #define PII pair<int,int> #define pb push_back #define mp make_pair #define fi first #define se second #define ll long long #define ull unsigned long long #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define MAX 1000005 #define MOD 1000000007 #define INF 0x3f3f3f3f #define lowbit(x) (x&-x) using namespace std; const int N = 1E5+20; int n,dp[N],A[N]; vector<int > vec[N]; int dfs(int x) { if(dp[x]!=-1) return dp[x]; int defa=0; for(int i=0;i<vec[x].size();i++) { if(!dfs(vec[x][i])) { defa=1; break; } } return dp[x]=defa; } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>A[i]; char c[N]; for(int i=1;i<=n;i++) { for(int j=i+A[i];j<=n;j=j+A[i]) if(A[j]>A[i]) vec[i].push_back(j); for(int j=i-A[i];j>=1;j=j-A[i]) if(A[j]>A[i]) vec[i].push_back(j); } memset(dp,-1,sizeof(dp)); for(int i=1;i<=n;i++) if(dp[i]==-1) dfs(i); for(int i=1;i<=n;i++) cout<<(dp[i]==1?'A':'B');//dp[i]=1代表必勝態 ,dp[i]代表必敗態 return 0; }