1. 程式人生 > >【博弈】[牛客練習賽 17] F 玩遊戲

【博弈】[牛客練習賽 17] F 玩遊戲

給定兩個串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");
	}
}