題意:Alice和Bob在玩一個遊戲,這個遊戲有個紙條,紙條的兩面有相同長度且由AB組成的字符串。每次其中一個人可以對摺一次紙條,直到不能再對摺爲止。如果最後紙條表面全是A則Alice獲勝,如果全是B則Bob獲勝,如果都不是則平局輸出Draw。Alice爲先手。
思路:dfs搜索,但是這裏也用到了博弈的知識。對摺每次只有偶數才能對摺,那麼結束條件就是紙條長度爲奇數的時候。這種兩面對摺,可以不用分兩個數組,一個數組直接相連就好了。(博弈知識)對於每個局面的先手,所以只要子結果裏面有一個是先手勝就ok了。而對於每個局面後手,必須要子結果全勝才能獲得出後手勝。那麼剩下的結果就是平局了。
代碼:
#include <algorithm>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=1e5*5+5;
char s[maxn*2];//把兩面合在一個數組裏面
int n;
int suma[maxn*2],sumb[maxn*2];//前綴和計算a,b的個數
int dfs(int l,int r,int t){
if((r-l+1)%2==1)return 2;
if(suma[r]-suma[l-1]==r-l+1)return 1;
if(sumb[r]-sumb[l-1]==r-l+1)return 0;
int mid=(l+r)/2;
int lson=dfs(l,mid,t^1);
int rson=dfs(mid+1,r,t^1);
if(lson==t||rson==t)return t;//先手只要子結果一個勝利就好了
if(lson==rson&&lson==(t^1))return t^1;
return 2;
}
int main(){
scanf("%d",&n);
scanf("%s",s+1);
scanf("%s",s+n+1);
for(int i=1;i<=2*n;i++){//前綴和計算a,b的個數
suma[i]=suma[i-1];
sumb[i]=sumb[i-1];
if(s[i]=='A')
suma[i]++;
else
sumb[i]++;
}
int ans=dfs(1,2*n,1);
if(ans==1) printf("Alice\n");
if(ans==0) printf("Bob\n");
if(ans==2) printf("Draw\n");
return 0;
}
總結:這道題,比賽的時候沒來得及看,但是感覺還是比較值得記錄以下的。一個是合併有關聯的數組簡化運算,還有前綴合和博弈局面先手後手必勝的條件使用。