loj #6377. 「是男人就过8题——Pony.ai」AStringGame
最近 Alice 和 Bob 在玩一个和字符串有关的游戏。在游戏开始之前,他们会准备 $n$ 个字符串 $s_1, s_2 \ldots s_n$ 和一个模板串 $t$, 保证这 $n$ 个字符串都是 $t$ 的子串。
游戏开始后,他们会轮流地执行以下操作,由 Alice 先手。
从 $n$ 个字符串中选择一个字符串 $s_i$;
在 $s_i$ 末尾增加一个字符;
得到的新字符串需要是 $t$ 的子串;
如果上述过程无法完成,当前玩家失败,假设 Alice 和 Bob 都以最优策略行动,求出谁是游戏的胜者。
本来以为是道神题……读了一遍题后发现是个板子题……
添加字符的操作相当于在 sam 上走一个节点,走不到节点的话就是输了
sam 是一个 DAG,因此在 DAG 上计算一下 SG 函数就行了
所有的查询子串的 SG 函数的异或和如果为正数,那么 Alice 获胜,否则 Bob 获胜
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 2e5 + 10; 4 int ch[N][26], len[N], pre[N], tot, last, n, sg[N], tmp[N]; char s[N]; bool vis[N]; 5 inline int nd(int l) { return len[++ tot] = l, memset(ch[tot], vis[tot] = 0, sizeof ch[tot]), tot; } 6 inline void ins(int c) { 7 int p, np, q, nq; 8 pre[last = np = nd(len[p = last] + 1)] = 1; 9 while(p && !ch[p][c]) ch[p][c] = np, p = pre[p]; 10 if(p) { 11 pre[np] = q = ch[p][c]; 12 if(len[p] + 1 != len[q]) { 13 pre[nq = nd(len[p] + 1)] = pre[q], memcpy(ch[pre[q] = pre[np] = nq], ch[q], sizeof ch[q]); 14 while(p && ch[p][c] == q) ch[p][c] = nq, p = pre[p]; 15 } 16 } 17 } 18 inline void dfs(int u) { 19 if(vis[u]) return ; 20 vis[u] = 1; 21 for(int c = 0 ; c < 26 ; ++ c) if(ch[u][c]) dfs(ch[u][c]); 22 int cnt = 0; 23 for(int c = 0 ; c < 26 ; ++ c) if(ch[u][c]) tmp[cnt ++] = sg[ch[u][c]]; 24 sg[u] = cnt; 25 if(cnt) { 26 sort(tmp, tmp + cnt), cnt = unique(tmp, tmp + cnt) - tmp; 27 sg[u] = cnt; 28 for(int i = 0 ; i < cnt ; ++ i) if(i != tmp[i]) { sg[u] = i; break; } 29 } 30 } 31 int main() { 32 while(scanf("%s%d", s + 1, &n) == 2) { 33 int ans = tot = 0; 34 last = nd(0); 35 for(int i = 1 ; s[i] ; ++ i) ins(s[i] - 'a'); 36 dfs(1); 37 for(int i = 1 ; i <= n ; ++ i) { 38 scanf("%s", s + 1); 39 int x = 1; 40 for(int j = 1 ; s[j] ; ++ j) x = ch[x][s[j] - 'a']; 41 ans ^= sg[x]; 42 } 43 puts(ans ? "Alice" : "Bob"); 44 } 45 }