fzu 2275 Game [第八届福建省大学生程序设计竞赛 Problem D]
题意: 对一个数字有两种操作: (1) 反转, (2) 除以 10 取整. 给你A, B两个数,Alice只能操作数字A,Bob只能操作数字B,如果Alice或Bob执行某次操作后A = B, Alice赢,否则就永远执行下去。
我的思路是a串和b串的后缀0都是无效的,因为经过有限次的操作之和后缀0是可以去掉的,比如100,可以通过操作1或操作2变成1。那么分几种情况讨论一下 在讨论前先把后缀0都去了,如果去了后缀0之后长度为0则说明这个串的元素就只有一个0,那么这个0不可以删除,就给它补回去 。下面开始讨论1.lenb>lena时alice不会赢,因为此时Bob可以一直执行操作1 2.lenb<=lena,用kmp或hash判断一下b串或b的翻转串是否是a串的子串,如果有一个满足,alice就可以通过操作1和操作2达到和b串相等,还有一个需要特判一下,就是b串=="0"时,不管a串是什么都可以变化到”0“,alice也可以赢,然后其他情况都是Bob赢了。
一组比较特殊的数据10 1000
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
#define cas(t) int t; scanf("%d",&t);
const int maxn = 1e5 + 10;
char A[maxn],B[maxn];
int next[maxn];
void getnext(int lent,char *f){
int i = 0,j = -1;
next[i] = -1;
while(i < lent){
if(j == -1 || f[i] == f[j])
i ++,j ++, next[i] = j;
else
j = next[j];
}
}
bool kmp(int lens,int lent,char *f){
for(int i = 0;i < lent + 10;i ++) next[i] = 0;
getnext(lent,f);
int i = 0,j = 0;
while((i < lens) && (j < lent)){
if(j == -1 || A[i] == f[j])
i ++,j ++;
else
j = next[j];
}
if(j == lent) return 1;
return 0;
}
int main()
{
cas(t);
while(t --){
scanf("%s %s",A,B);
int lenb = strlen(B);
int lena = strlen(A);
for(int i=lena-1;i>=0;i--)
{
if(A[i]!='0')
break;
else
A[i]=0;
}
for(int i=lenb-1;i>=0;i--)
{
if(B[i]!='0')
break;
else
B[i]=0;
}
lenb = strlen(B);
lena = strlen(A);
if(lena==0)
A[0]='0';
if(lenb==0)
B[0]='0';
lenb = strlen(B);
lena = strlen(A);
if(lena < lenb){ //情况1
cout<<"Bob"<<endl;
continue;
}
char C[maxn] = {0};
int p = 0;
for(int i = lenb - 1;i >= 0;i --)
C[p ++] = B[i];
// cout<<A<<endl<<B<<endl<<C<<endl<<lena<<endl<<lenb<<endl<<p<<endl;
if(B[0]=='0'||kmp(lena,lenb,B) != 0||kmp(lena,p,C) != 0)//情况2
printf("Alice\n");
else
printf("Bob\n");
}
return 0;
}