FZU - 2275 - Game - (KMP)

题目链接: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;
}


猜你喜欢

转载自blog.csdn.net/sdau20163942/article/details/80117867
今日推荐