[GDOI2017]微信(广义SAM+状态压缩)

[GDOI2017]微信(广义SAM+状态压缩)

题面

题面过长,略

分析

先把n个串合并建出Trie. 由于n很小,对于Trie的每个节点,我们用状压记录这个节点代表的子串来自哪些串。然后BFS这个Trie,建出广义SAM.对于SAM中新建的每个节点,同样维护这个子串来自哪些串,构建的时候把它赋值为原Trie上的状态(复制出来的节点为0).然后在parent树上,把子树中的状态并上来。

接着设(f[S])表示询问的串状态为(S)的答案。设后缀自动机上每个点的状态为(S_x),我们初始化(f[S_x]=len(x)).那么由于x代表在(S_x)中的每个串都存在,那么在(S_x)的子集中的每个串都存在。我们可以用(f[S_x])去更新(f[S_x-{ i}]),即:

[f[S-{ i}]=min(f[S-{ i}],f[S]) ]

对于询问,直接输出对应的(f)即可。时间复杂度(O(sum |S|+2^n))

代码

#include<iostream>
#include<cstdio>
#include<cstring> 
#include<queue>
#define maxn 2000000
#define maxc 26
#define maxs (1<<20)
using namespace std;
int n,m;
char in[maxn+5];

struct EXSAM{
#define len(x) t[x].len
#define link(x) t[x].link 
	struct node {
		int ch[maxc];
		int link;
		int len;
		int sta;
	} t[maxn*2+5];
	const int root=1;
	int ptr=1;
	int extend(int last,int c,int sta) {
		int p=last,cur=++ptr;
		len(cur)=len(p)+1;
		t[cur].sta=sta;
		while(p&&t[p].ch[c]==0) {
			t[p].ch[c]=cur;
			p=link(p);
		}
		if(p==0) link(cur)=root;
		else {
			int q=t[p].ch[c];
			if(len(p)+1==len(q)) link(cur)=q;
			else {
				int clo=++ptr;
				len(clo)=len(p)+1;
				for(int i=0; i<maxc; i++) t[clo].ch[i]=t[q].ch[i];
				link(clo)=link(q);
				link(q)=link(cur)=clo;
				while(p&&t[p].ch[c]==q) {
					t[p].ch[c]=clo;
					p=link(p);
				}
			}
		}
		return cur;
	}
	void topo_sort(){
		static int in[maxn+5];
		queue<int>q;
		for(int i=1;i<=ptr;i++) in[link(i)]++;
		for(int i=1;i<=ptr;i++) if(!in[i]) q.push(i);
		while(!q.empty()){
			int x=q.front();
			q.pop();
			in[link(x)]--;
			t[link(x)].sta|=t[x].sta;
			if(in[link(x)]==0) q.push(link(x));
		}
	}
}T1;
struct Trie{
	int trie_pos[maxn+5],sam_pos[maxn+5];
	int ch[maxn+5][maxc];
	int sta[maxn+5];
	const int root=1;
	int ptr=1;
	void insert(char *s,int id){
		int top=0; 
		int len=strlen(s+1);
		trie_pos[++top]=root;
		for(int i=1;i<=len;i++){
			if(s[i]=='<') top--;
			else{
				int x=trie_pos[top],c=s[i]-'a';
				if(!ch[x][c]) ch[x][c]=++ptr;
				x=ch[x][c];
				sta[x]|=(1<<(id-1)); 
				trie_pos[++top]=x;
			}
		}
	}
	void build(EXSAM &T1){
		queue<int>q;
		q.push(root);
		sam_pos[root]=root;
		while(!q.empty()){
			int x=q.front();
			q.pop();
			for(int i=0;i<maxc;i++){
				int y=ch[x][i];
				if(y!=0){
					sam_pos[y]=T1.extend(sam_pos[x],i,sta[y]);
					q.push(y);
				}
			}
		}
	}
}T2; 
int dp[maxs+5];
int query(char *s){
	int len=strlen(s+1);
	int x=0;
	for(int i=len;i>=1;i--) x=x*2+s[i]-'0';
	return dp[x];
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",in+1);
		T2.insert(in,i);
	}
	T2.build(T1);
	T1.topo_sort();
	for(int i=1;i<=T1.ptr;i++) dp[T1.t[i].sta]=max(dp[T1.t[i].sta],T1.t[i].len);
	for(int i=(1<<n)-1;i>=0;i--){
		for(int j=0;j<n;j++){
			if(i&(1<<j)) dp[i^(1<<j)]=max(dp[i^(1<<j)],dp[i]);
			//如果一个串的出现状态为i
			//那么询问它的子集i^(1<<j)的答案,就可以用这个串去更新 
		}
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		scanf("%s",in+1);
		printf("%d
",query(in));
	}
}
/*
2
ab<a
aac
2
01 
*/

原文地址:https://www.cnblogs.com/birchtree/p/12555638.html