题目链接:http://acm.fzu.edu.cn/problem.php?pid=2275
题解来自:https://blog.csdn.net/qq_33184171/article/details/75687721
题意:给你两个大数,(不含前导零), 两个人轮流操作自己的数,可以除以10(向下取整,没有小数.)或者翻转过去,(翻转之后要去掉前导0)。当有一时刻两个数相等则A赢,否则B赢,所以A想要将两个数变得相同,B想讲两个数变得不同.问你两个人最后谁赢。
解析:考虑到如果B想让两个数不等那么只能是在A中没有B的子串才行,否则A不断的翻转在除以10一定会有一个时刻和B相同,这时候无论B怎么翻转还是除10,最终的一定会有一个时刻相等,
所以只要用kmp匹配一下A的数是否有B或者翻转的B就行了
注意的是 B的数 如果翻转就相当去去掉了后面的0,所以在匹配之前除了一下B,使两端都没有0;
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; #define M 1000005 char s[M],s2[M]; int nexts[M*2+M/10]; void getn() { int len=strlen(s2); int i=0,j; j=nexts[0]=-1; for(i=0;i<len;) { if(j==-1 || s2[i]==s2[j]) nexts[++i]=++j; else j=nexts[j]; } } bool kmp() { getn(); int len1=strlen(s),len2=strlen(s2); int i=0,j=0; for(i=0;i<len1;) { if(j==-1||s[i]==s2[j]) { i++; j++; } else j=nexts[j]; if(j>=len2) return 1; } if(j>=len2) return 1; return 0; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%s%s",s,s2); bool flag=true; //s2是否全为0 for(int i=0;s2[i];i++) { if(s2[i]!='0') { flag=false; break; } } int len2=strlen(s2); for(int i=len2-1;i>=0;i--) //去掉尾部的0 { if(s2[i]=='0') s2[i]='\0'; else break; } if(flag||kmp()) { printf("Alice\n"); }else{ reverse(s2,s2+strlen(s2)); if(kmp()) printf("Alice\n"); else printf("Bob\n"); } } return 0; }