Newcoder 109 F.玩游戏(博弈论)

本文探讨了一种基于串匹配的游戏,玩家通过删除串的首位字符进行回合制操作,目标是使剩余串与目标串匹配。文章提供了判断最终胜者的算法,并通过代码实现了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给定两个串SSSTTT∣S∣≥∣T∣|S|\ge |T|ST

alicealicealicebobbobbob轮流操作串SSSbobbobbob先手。

对于每次操作,alicealicealicebobbobbob会选择删掉SSS的第一位或最后一位。

当操作以后的串的长度等于∣T∣|T|T时,游戏停止。

如果停止时的串=T=T=T,则alicealicealice获胜,否则bobbobbob获胜。

问在alicealicealicebobbobbob均采取最优策略的情况下,谁赢?

Input

第一行一个整数TTT表示数据组数。

接下来TTT行每行两个整数字符串S,TS, TS,T

(T≤1000,1≤∣T∣≤∣S∣≤5⋅105,∑(∣S∣+∣T∣)≤106)(T\le 1000,1\le |T|\le |S|\le 5\cdot 10^5,\sum(|S|+|T|)\le 10^6)(T1000,1TS5105,(S+T)106)

Output

TTT行。对于每组数据,alicealicealice赢输出′Alice′'Alice'Alice,$ bob赢输出赢输出’Bob’$。

Sample Input

5
aba b
bab b
aaab aab
xyz mnk
xyz xyz

Sample Output

Alice
Alice
Bob
Bob
Alice

Solution

一.若∣S∣=∣T∣|S|=|T|S=T,此时S=TS=TS=T则后手胜,否则先手胜

二.若∣S∣>∣T∣|S|>|T|S>T,记n=∣S∣,m=∣T∣,t=n−mn=|S|,m=|T|,t=n-mn=S,m=T,t=nm,那么先手可以操作x=⌈t2⌉x=\lceil\frac{t}{2}\rceilx=2t次,后手可以操作y=⌊t2⌋y=\lfloor\frac{t}{2}\rfloory=2t次,记[li,ri][l_i,r_i][li,ri]SSS中所有可以与TTT匹配的区间,那么有li−1+n−ri=tl_i-1+n-r_i=tli1+nri=t

1.若ttt为偶数,那么x=yx=yx=y,我们首先证明先手必然可以破坏所有满足li−1̸∈[x−1,x+1]l_i-1\not\in[x-1,x+1]li1̸[x1,x+1]的匹配,先手首先任选一边删去一个,之后后手删哪边先手就删另一边,这样可以保证两边都至少删去了x−1x-1x1次,那么所有这种匹配都会因为li−1&lt;x−1l_i-1&lt;x-1li1<x1n−ri&lt;x−1n-r_i&lt;x-1nri<x1被破坏

注意到先手可以破坏一边至多xxx次,故对于li−1=xl_i-1=xli1=x的匹配显然可以保存下来,但是对于li−1=x±1l_i-1=x\pm 1li1=x±1的情况,如果只存在一个匹配满足该条件,那么先手只需尽可能删除一边即可破坏该匹配,故此时必须至少存在两个匹配使得li−1=x−1,lj−1=x+1l_i-1=x-1,l_j-1=x+1li1=x1,lj1=x+1,如此先手无论怎么删都至少会有一个匹配保存下来

2.若ttt为奇数,那么x=y+1x=y+1x=y+1,同理至少需要两个匹配使得li−1=x,lj−1=x+1l_i-1=x,l_j-1=x+1li1=x,lj1=x+1,这样先手无论删哪一边,只要后手删另一边,就可以保证至少有一个匹配保存下来

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500005;
int T,n,m;
char s[maxn],t[maxn];
bool check(int x)
{
	for(int i=x+1,j=1;j<=m;i++,j++)
		if(s[i]!=t[j])return 0;
	return 1;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s%s",s+1,t+1);
		n=strlen(s+1),m=strlen(t+1); 
		int flag=0;
		if(n==m)
		{
			if(strcmp(s+1,t+1)==0)flag=1;
		}
		else
		{
			if((n-m)&1)
			{
				if(check((n-m)/2)&&check((n-m)/2+1))flag=1;
			}
			else 
			{
				if(check((n-m)/2)||check((n-m)/2-1)&&check((n-m)/2+1))flag=1;
			}
		}
		if(flag)printf("Alice\n");
		else printf("Bob\n");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值