是男人就过 8 题--Pony.AI 题A String Game(博弈 SG 后缀自动机)

将每个单轮的SG函数抑或可得最终结果。

为了计算SG函数,先对主串用后缀自动机处理,对输入的每个子串,先在自动机上走到对应串的节点,然后枚举后续状态,这些状态即为SG函数对应的后继状态,求SG函数,并将结果保存,否则会超时。

 

//http://www.cnblogs.com/IMGavin/
//https://nanti.jisuanke.com/t/24852
#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#include <algorithm>
using namespace std;

typedef long long LL;
#define gets(A) fgets(A, 1e8, stdin)
const int INF = 0x3F3F3F3F, N = 200008, MOD = 1003;

const int CH = 26;

struct Node{
	int ch[CH], fa, len, sg;
	void init(){
		fa = -1;
		len = 0;
		sg = -1;
		memset(ch, 0xff, sizeof(ch));
	}
}sn[N];

struct SAM{
	int cnt, last;
	SAM(){
		cnt = last = 0;
		sn[cnt++].init();
	}

	int newnode(){
		sn[cnt].init();
		return cnt++;
	}

	void add(int x){
		//当前串T,加入字符x,p=ST(T),end=ST(Tx)
		int end = newnode();
		sn[end].len = sn[last].len + 1;
		int v = last;
		//对p的所有没有标号x边的祖先v,trans(v,x) = end
		for(; v != -1 && sn[v].ch[x] == -1; v = sn[v].fa){
			sn[v].ch[x] = end;
		}
		//查找p的第一个有x边的祖先v,若无,则fa[end]=root
		if(v == -1){
			sn[end].fa = 0;
		}else{
			//q=trans(v,x)若Max(q)==Max(v)+1,则fa[end]=q
			int q = sn[v].ch[x];
			if(sn[v].len + 1 == sn[q].len){
				sn[end].fa = q;
			}else{
				//否则新建节点nq,trans(nq,*)=trans(q,x)
				//祖先关系由q->fa[q],改为q->nq->fa[q](更改前的fa[q])
				int nq = newnode();
				sn[nq] = sn[q];
				sn[nq].len = sn[v].len + 1;
				sn[end].fa = sn[q].fa = nq;
				//对trans(v,x)==q的v,trans(v,x)改为nq
				for(; v != -1 && sn[v].ch[x] == q; v = sn[v].fa){
					sn[v].ch[x] = nq;
				}

			}
		}

		last = end;
	}

};

char str[N], p[N];

int dfs(int d){
	if(sn[d].sg != -1){
		return sn[d].sg;
	}
	bool st[27];
	memset(st, 0, sizeof(st));
	for(int i = 0; i < 26; i++){
		if(sn[d].ch[i] != -1){
			int sg = dfs(sn[d].ch[i]);
			if(sg <= 26){
				st[sg] = true;
			}
		}
	}
	for(int i = 0; i <= 26; i++){
		if(!st[i]){
			sn[d].sg = i;
			return i;
		}
	}

}

int main(){
	//freopen("out.txt", "w", stdout);
	while(~scanf("%s", str)){
		SAM sa;
		for(int i = 0; str[i]; i++){
			sa.add(str[i] - 'a');
		}
		int t, ans = 0;
		scanf("%d", &t);
		while(t--){
			scanf("%s", p);
			int st = 0;
			for(int i = 0; p[i]; i++){
				st = sn[st].ch[p[i] - 'a'];
			}
			ans ^= dfs(st);
		}
		if(ans){
			printf("Alice\n");
		}else{
			printf("Bob\n");
		}

	}
	

	return 0;
}

  

posted @ 2018-08-11 12:07  vwirtveurit  阅读(476)  评论(0编辑  收藏  举报