【计蒜客】是男人就过 8 题--Pony.AI 题 A. A String Game 后缀自动机+SG函数

【题目】A. A String Game

【题意】给定目标串S和n个子串Ti,Alice和Bob轮流选择一个子串操作,必须且只能在子串末尾添加一个字符使得新串也是S的子串,不能操作即输,求胜利者。|S|<=10^5,n<=100。多组数据,保证Σ|S|<=3*10^7。

【算法】后缀自动机+博弈论SG函数

【题解】对S建SAM,每次子串操作相当于沿SAM的实边走,所以可以对SAM进行DAG上的sg函数计算,最后多个子串的sg值的异或和就是答案,非0先手必胜。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#define ll long long
#define lowbit(x) x&-x
using namespace std;
int read(){
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c=='-')t=-1;
    do{s=s*10+c-'0';}while(isdigit(c=getchar()));
    return s*t;
}
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a<b?b:a;}
int ab(int x){return x>0?x:-x;}
//int MO(int x){return x>=MOD?x-MOD:x;}
//void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
/*------------------------------------------------------------*/
const int inf=0x3f3f3f3f,maxn=100010;

int n,last,root,size,sg[maxn*2];
struct st{int len,fa,t[30];}t[maxn*2];
void insert(int c){
    int np=++size;
    for(int i=0;i<26;i++)t[np].t[i]=0;
    t[np].len=t[last].len+1;
    int x=last;
    while(x&&!t[x].t[c])t[x].t[c]=np,x=t[x].fa;
    last=np;
    if(!x)t[np].fa=root;else{
        int y=t[x].t[c];
        if(t[y].len==t[x].len+1)t[np].fa=y;else{
            int nq=++size;
            t[nq]=t[y];
            t[nq].len=t[x].len+1;
            t[nq].fa=t[y].fa;t[y].fa=t[np].fa=nq;
            while(x&&t[x].t[c]==y)t[x].t[c]=nq,x=t[x].fa;
        }
    }
}
void dfs(int x){
    bool vis[28];//
    if(~sg[x])return;
    memset(vis,0,sizeof(vis));
    for(int c=0;c<26;c++)if(t[x].t[c]){
        dfs(t[x].t[c]);
        vis[sg[t[x].t[c]]]=1;
    }
    for(int i=0;i<=26;i++)if(!vis[i]){sg[x]=i;break;}
}
char s[maxn];
int main(){
    while(~scanf("%s",s)){
        int m=strlen(s);
        last=size=root=1;
        for(int c=0;c<26;c++)t[1].t[c]=0;
        for(int i=0;i<m;i++)insert(s[i]-'a');
        memset(sg,-1,sizeof(sg));
        dfs(root);
        n=read();
        int ans=0;
        for(int i=1;i<=n;i++){
            int x=root;
            scanf("%s",s);m=strlen(s);
            for(int j=0;j<m;j++)x=t[x].t[s[j]-'a'];
            ans^=sg[x];
        }
        if(ans)printf("Alice\n");else printf("Bob\n");
    }
    return 0;
}
View Code

 

这破题说明我是八分之一男人,哈哈哈嗝。

。。。

posted @ 2018-03-28 22:27  ONION_CYC  阅读(1033)  评论(0编辑  收藏  举报