题目描述:
这一天,小A和小B在玩一个游戏,他俩每人都有一个整数,然后两人轮流对他们的整数进行操作,每次在下列两个操作任选一个:
(1)对整数进行翻转,如1234翻转成4321 ,1200翻转成21
(2)将整数除以10,如1234/10=123,1/10=0
当操作过程中出现a==b时,则小A就赢了,而操作一直进行下去或不能使a==b则算小B赢。
现在小A求助于你,想让你帮他在知道两人的整数时小A能不能赢,假设每次都是小A先手,并且两人都是采取最优策略
Input
首先输入T(T <= 100),表示有T组数据,然后接下来有T行,每行有两个整数a,b(0 <= a,b < 10100000)
Output
有T行,当小A赢了则输出"Yes",否则输出"No"
Sample Input
4
1234 123
123 321
1234 12345
123 123
Sample Output
Yes
Yes
No
Yes
题目思路:
其实如果这道题不是放在KMP专题里面,我应该是完全想不到用KMP的(嘤)。
既然他们都采取的时最优策略,我们就可以这样考虑:B要怎么做才能不让A胜利。由于A采取的也是最优策略,那么可以知道,而且可以翻转和切掉最后的数字,注意:翻转+切掉最后的数字也就是告诉我们,A可以得到所有它的子串。那么,如果B或者B翻转之后是A的子串,那么A就一定可以通过翻转和切掉数字的操作是自己的数字等于B!
这里不用考虑B的子串是因为:B采取的也是最优策略,如果它的子串是A的子串,那么A肯定可以得到,B是绝对不会这样做的。
需要注意的一点是:翻转之后的前导0要去掉,比如1200翻转后是21,处理一下就好。
另:STL中的翻转函数reverse
题目代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define maxn 1000005
using namespace std;
char a[maxn],b[maxn];
int nxt[maxn];
void build(char s[],int n)
{
int k=0;nxt[0]=0;
for(int i=1;i<n;i++)
{
while(k&&s[i]!=s[k])
k=nxt[k-1];
if(s[i]==s[k])
k++;
nxt[i]=k;
}
}
bool kmp(char w[],char s[],int lw,int ls)
{
build(s,ls);
int j=0;
for(int i=0;i<lw;i++)
{
while(j&&w[i]!=s[j])
j=nxt[j-1];
if(w[i]==s[j])
j++;
if(j==ls)
return true;
}
return false;
}
int main(void)
{
int t;
int k,flag;
scanf("%d",&t);
while(t--)
{
memset(nxt,0,sizeof(nxt));
scanf("%s%s",a,b);
int la=strlen(a);
int lb=strlen(b);
for(int i=la-1;i>=0;--i)//去掉A后面的0
{
if(a[i]!='0')
break;
a[i]='\0';
}
la=strlen(a);
for(int i=lb-1;i>=0;--i)//去掉B后面的0,为了方便后面翻转
{
if(b[i]!='0')
break;
b[i]='\0';
}
lb=strlen(b);
if(lb>la)//如果B的长度大于A显然不会
{
printf("No\n");
continue;
}
if(lb==0||kmp(a,b,la,lb))//看B是不是A的子串
{
printf("Yes\n");
continue;
}
reverse(b,b+lb);
//puts(b);
memset(nxt,0,sizeof(nxt));
if(kmp(a,b,la,lb))//看B的翻转是不是A的子串
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
呼呼