计蒜客 A String Game SG函数+后缀自动机

题意

给出一个串 t n t 的子串 s [ 1.. n ] 。两个人轮流操作,每次可以选择一个串 s [ i ] ,然后在 s [ i ] 的最后添上一个字符串,满足得到的新串仍然是t的子串。不能操作者输,问先手必胜还是后手必胜。
t 10 5 , | s [ i ] | 3 10 7

分析

楼教是男人就过8题中最简单的一道题,怎么说我也已经是 1 8 个男人了。
先把后缀自动机建出来,在一个串后面添加字符等价于把其在sam上的对应节点在DAG上后移一位。
那么我们可以先预处理出后缀自动机上每个点的SG值,然后每个字符串的SG值异或和即为答案。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>

const int N=200005;

int sz,last,mx[N],ch[N][26],a[N],deg[N],fa[N],sg[N],t[N];
char str[30000005];
std::queue<int> que;

void extend(int x)
{
    int p,q,np,nq;
    p=last;last=np=++sz;mx[np]=mx[p]+1;
    for (;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
    if (!p) fa[np]=1;
    else
    {
        q=ch[p][x];
        if (mx[q]==mx[p]+1) fa[np]=q;
        else
        {
            nq=++sz;mx[nq]=mx[p]+1;
            memcpy(ch[nq],ch[q],sizeof(ch[q]));
            fa[nq]=fa[q];fa[q]=fa[np]=nq;
            for (;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
        }
    }
}

void pre()
{
    for (int i=1;i<=sz;i++) deg[i]=sg[i]=0;
    for (int i=1;i<=sz;i++)
        for (int j=0;j<26;j++)
            if (ch[i][j]) deg[ch[i][j]]++;
    for (int i=1;i<=sz;i++) if (!deg[i]) que.push(i);
    int tot=0;
    while (!que.empty())
    {
        int x=que.front();que.pop();
        a[++tot]=x;
        for (int i=0;i<26;i++)
            if (ch[x][i])
            {
                deg[ch[x][i]]--;
                if (!deg[ch[x][i]]) que.push(ch[x][i]);
            }
    }
    for (int i=sz;i>=1;i--)
    {
        int x=a[i];
        for (int j=0;j<26;j++)
            if (ch[x][j]) t[sg[ch[x][j]]]=1;
        for (int j=0;;j++) if (!t[j]) {sg[x]=j;break;}
        for (int j=0;j<26;j++)
            if (ch[x][j]) t[sg[ch[x][j]]]=0;
    }
}

int main()
{
    while (scanf("%s",str)!=EOF)
    {
        for (int i=1;i<=sz;i++)
            for (int j=0;j<26;j++)
                ch[i][j]=0;
        for (int i=1;i<=sz;i++) fa[i]=mx[i]=0;
        sz=last=1;
        int len=strlen(str);
        for (int i=0;i<len;i++) extend(str[i]-'a');
        pre();
        int n,ans=0;
        scanf("%d",&n);
        while (n--)
        {
            scanf("%s",str);len=strlen(str);
            int x=1;
            for (int i=0;i<len;i++) x=ch[x][str[i]-'a'];
            ans^=sg[x];
        }
        puts(ans?"Alice":"Bob");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_33229466/article/details/80055211