题目链接: A String Game
sol:
一眼
定理,可惜那时候不怎么会后缀自动机,拿后缀数组暴力转移失败
对
串建立后缀自动机,每个状态结点都表示一种局面,其后继状态即其在自动机上的合法转移结点。拓扑排序后通过
定理求出每个结点的
值。考虑单个字符串
,其
值即为自动机上
对应子串结点的
值。答案就是所有串的
和。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6+5;
const int s_sz = 26;
const int inf = 0x3f3f3f3f;
#define fi first
#define se second
#define MP make_pair
#define pii pair<int,int>
int sum[maxn],tmp[maxn];
char str[maxn];
char s1[maxn];
struct SAM{
int ch[maxn][s_sz];
int rt,sz,last;
int len[maxn],suf[maxn],r[maxn],sg[maxn];
void init(){
memset(ch,0,sizeof(ch[0]) * (sz+1));
memset(suf,0,sizeof(int)*(sz+1));
memset(r,0,sizeof(int)*(sz+1));
rt = sz = last = 1;
}
inline void add(int x,int c){
int p = last,np = ++sz;
last = np;
len[np] = x;
while(p && !ch[p][c]){
ch[p][c] = np;
p = suf[p];
}
if(!p){
suf[np] = rt;
return;
}
int q = ch[p][c];
if(len[q] == len[p] + 1) suf[np] = q;
else{
int nq = ++ sz;
len[nq] = len[p] + 1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
suf[nq] = suf[q];
suf[np] = suf[q] = nq;
while(ch[p][c] == q){
ch[p][c] = nq;
p = suf[p];
}
}
}
inline int idx(char c){
return c - 'a';
}
inline void build(char* s){
int n = strlen(s);
for(int i = 0;i<n;i++){
add(i+1,idx(s[i]));
}
}
inline void Topsort(int n){
memset(sum,0,sizeof(int)*(n+1));
for(int i = 1;i<=sz;i++) sum[len[i]] ++ ;
for(int i = 1;i<=n;i++) sum[i] += sum[i-1];
for(int i = 1;i<=sz;i++) tmp[sum[len[i]]--] = i;
}
void get_sg(){
for(int i = sz;i;i--){
int u = tmp[i];
set<int> ss;
for(int c = 0; c< s_sz;c++){
int v = ch[u][c];
if(v) {
ss.insert(sg[v]);
}
}
for(int j = 0;;j++){
if(!ss.count(j)) {
sg[u] = j;
break;
}
}
}
}
int work(char * s){
int n = strlen(s);
int u = rt;
for(int i = 0;i<n;i++){
u = ch[u][idx(s[i])];
if(!u) return 0;
}
return sg[u];
}
}sam;
int main(){
while(scanf("%s",str)==1){
sam.init();
sam.build(str);
sam.Topsort(strlen(str));
sam.get_sg();
int n;
scanf("%d",&n);
int ret = 0;
while(n--){
scanf("%s",s1);
ret ^= sam.work(s1);
}
if(ret>0) puts("Alice");
else puts("Bob");
}
return 0;
}