Description
最近 Alice 和 Bob 在玩一个和字符串有关的游戏。在游戏开始之前,他们会准备 n个字符串 s1~sn,和一个模板串 t, 保证这 n 个字符串都是 t 的子串。
游戏开始后,他们会轮流地执行以下操作,由 Alice 先手。
- 从 n 个字符串中选择一个字符串 si
- 在 si 末尾增加一个字符;
得到的新字符串需要是 t 的子串;
如果上述过程无法完成,当前玩家失败,假设 Alice 和 Bob 都以最优策略行动,求出谁是游戏的胜者。
|t|<=1e5,∑|si|<=3e7
Solution
把模板串的sam建出来,那么添加字符相当于在sam上转移。那么我们直接在sam上求sg就行了
新男人八题,我也是1/8个男人了
Code
// A String Game
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define copy(x,t) memcpy(x,t,sizeof(x))
const int N=200055;
int rec[N][26],len[N],fa[N];
int sg[N],tot,last;
char str[N],ptr[N];
void ins(int ch) {
int p,q,np,nq;
p=last; last=np=++tot; len[np]=len[p]+1;
fill(rec[tot],0); fa[tot]=0;
for (;p&&!rec[p][ch];p=fa[p]) rec[p][ch]=np;
if (!p) fa[np]=1;
else {
q=rec[p][ch];
if (len[p]+1==len[q]) fa[np]=q;
else {
nq=++tot; len[nq]=len[p]+1;
fill(rec[tot],0); fa[tot]=0;
copy(rec[nq],rec[q]);
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
for (;p&&rec[p][ch]==q;p=fa[p]) rec[p][ch]=nq;
}
}
}
void get_sg(int now) {
if (~sg[now]) return ;
bool vis[30]; fill(vis,false);
rep(i,0,25) {
int tar=rec[now][i];
if (tar) {
get_sg(tar);
vis[sg[tar]]=true;
}
}
for (int i=0;;i++) if (!vis[i]) return (void) (sg[now]=i);
}
int main(void) {
while (~scanf("%s",str+1)) {
int n,lens=strlen(str+1); scanf("%d",&n);
tot=last=1; fill(rec[tot],0); fa[tot]=0;
rep(i,1,lens) {
ins(str[i]-'a');
}
fill(sg,-1);
get_sg(1); int ans=0;
rep(i,1,n) {
scanf("%s",ptr+1);
int lenp=strlen(ptr+1),now=1;
rep(j,1,lenp) now=rec[now][ptr[j]-'a'];
ans^=sg[now];
}
if (ans) puts("Alice");
else puts("Bob");
}
return 0;
}