题目链接:
点击打开链接
解题思路:在后缀自动机的有向图上建立SG函数,然后去求每个子串在树上的节点号,异或个各个节点号sg值就行了。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mx = 2e5 + 10;
int n,m,a[mx],tot,last,ma[mx],mi[mx];
int fa[mx],id[mx][28],len[mx];
int sg[mx];
char str[mx],Ts[mx];
void init()
{
last = tot = 1;
fa[1] = len[1] = 0;
memset(id[1],0,sizeof(id[1]));
memset(sg,-1,sizeof(sg));
//memset(v,0,sizeof(v));
}
void suf_auto(int ch)
{
int np = ++tot,p = last;
memset(id[np],0,sizeof(id[np]));
len[np] = len[last] + 1,last = np;
while(p&&!id[p][ch]) id[p][ch] = np,p = fa[p];
if(!p) fa[np] = 1;
else{
int q = id[p][ch];
if(len[p]+1==len[q]) fa[np] = q;
else{
int nq = ++tot;
copy(id[q],id[q]+sizeof(id[q]),id[nq]);
fa[nq] = fa[q];
len[nq] = len[p] + 1;
fa[q] = fa[np] = nq;
while(p&&id[p][ch]==q) id[p][ch] = nq,p = fa[p];
}
}
}
void get_sg(int x)
{
bool vis[30];
for(int i=0;i<30;i++) vis[i] = 0;
for(int i=0;i<26;i++){
if(!id[x][i]) continue;
if(sg[id[x][i]]==-1) get_sg(id[x][i]);
vis[sg[id[x][i]]] = 1;
}
for(int i=0;i<27;i++) if(!vis[i])
{
sg[x] = i;
break;
}
}
int get_node(char *p)
{
int lon = strlen(p);
int root = 1;
for(int i=0;i<lon;i++){
root = id[root][p[i]-'a'];
}
return root;
}
int main()
{
while(~scanf("%s",str)){
init();
int lon = strlen(str);
for(int i=0;i<lon;i++) suf_auto(str[i]-'a');
get_sg(1);
scanf("%d",&m);
int ans = 0;
while(m--){
scanf("%s",Ts);
int k = get_node(Ts);
ans ^= sg[k];
}
puts(ans?"Alice":"Bob");
}
return 0;
}