是男人就过 8 题--Pony.AI A String Game

题目链接: A String Game

在这里插入图片描述

sol:

一眼 s g sg 定理,可惜那时候不怎么会后缀自动机,拿后缀数组暴力转移失败
t t 串建立后缀自动机,每个状态结点都表示一种局面,其后继状态即其在自动机上的合法转移结点。拓扑排序后通过 s g sg 定理求出每个结点的 s g sg 值。考虑单个字符串 s s ,其 s g sg 值即为自动机上 s s 对应子串结点的 s g sg 值。答案就是所有串的 N i m Nim 和。

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;
}

猜你喜欢

转载自blog.csdn.net/oWuHen12/article/details/82780444