【博弈】[牛客練習賽 17] F 玩遊戲
阿新 • • 發佈:2018-12-16
給定兩個串S和T,|S| >= |T|。 alice和bob輪流操作串S,bob先手。 對於每次操作,alice或bob會選擇刪掉S的第一位或最後一位。 當操作以後的串的長度等於|T|時,遊戲停止。 如果停止時的串=T,則alice獲勝,否則bob獲勝。 問在alice和bob均採取最優策略的情況下,誰贏?
t組資料 1<=|T|<=|S|<=500000,t<=1000 字串總長度不超過1000000 ##Solution 考慮簡化表示狀態
設左邊已經刪掉了L個數,右邊已經刪掉了R個數 那麼用R-L來表示當前狀態,可以用KMP求出有哪些目標狀態
一開始R-L為0,每一次操作可以讓它+1或者-1,雙方輪流操作,總共|S|-|T|次操作,雙方都用最優策略看最後是否能到達目標狀態
顯然所有的目標狀態奇偶性相同
當|S|-|T|為奇數時,最後一次操作是Bob做,它肯定往不是目標狀態走,那麼一個位置在最後一次操作前是目標狀態當且僅當它+1它-1都是目標狀態
現在就全部轉化成|S|-|T|為偶數的情況
假如0是目標狀態,那麼顯然Alice會贏,無論Bob往哪裡走Alice後手都可以把他拉回來
如果0不是,並且-2和2不全是,那麼Bob一定會朝不是的那一邊走,Alice無論如何都沒有辦法將它拉回到是的那一邊了
因此Alice會贏當且僅當0是目標狀態或者-2和2都是目標狀態 否則都是Bob贏 ##Code
#include <cstdio> #include <iostream> #include <algorithm> #include <cstdlib> #include <cmath> #include <cstring> #define fo(i,a,b) for(int i=a;i<=b;++i) #define fod(i,a,b) for(int i=a;i>=b;--i) #define N 500005 using namespace std; int n,m,t,cnt[N],nx[N],ct[N]; char st[N],ch[N]; void kmp() { n=strlen(st+1),m=strlen(ch+1); int j=0; fo(i,2,m) { while(j&&ch[i]!=ch[j+1]) j=nx[j]; if(ch[i]==ch[j+1]) j++; nx[i]=j; } j=0; fo(i,1,n) { while(j&&st[i]!=ch[j+1]) j=nx[j]; if(st[i]==ch[j+1]) j++; if(j==m) { if((n-m)%2==0) cnt[++cnt[0]]=n-i-(i-m); else ct[++ct[0]]=n-i-(i-m); j=nx[j]; } } } int main() { cin>>t; while(t--) { scanf("\n%s",st+1); scanf("%s",ch+1); cnt[0]=0,ct[0]=0; kmp(); if((n-m)%2!=0) { sort(ct+1,ct+ct[0]+1); fo(i,2,ct[0]) if(ct[i]-ct[i-1]==2) cnt[++cnt[0]]=ct[i]-1; } bool pd=0,pd1=0,pd2=0; fo(i,1,cnt[0]) { if(cnt[i]==0) pd=1; if(cnt[i]==2) pd1=1; if(cnt[i]==-2) pd2=1; } if(pd||(pd1&&pd2)) printf("Alice\n"); else printf("Bob\n"); } }