[HNOI2006]最短母串问题

[HNOI2006]最短母串问题

好题。

首先建立AC自动机。然后就不会了。

观察到\(n\)很小,是状压的级别。

考虑将自动机中的\(fin\)变量升级为\(state\)变量,表示从当前节点出发,能否到达各字符串。

\(ins\)时,有

void ins(int id){
	int x=1;
	for(int i=0;i<S;i++){
		if(!t[x].ch[s[i]-'A'])t[x].ch[s[i]-'A']=++cnt;
		x=t[x].ch[s[i]-'A'];
	}
	t[x].state|=(1<<id);
}

注意到最后一句的变化。

\(build\)时,因为该节点的\(fail\)树上的所有祖先都是可到达的,我们就可以暴力回跳更新\(state\)

void build(){
	for(int i=0;i<26;i++){
		if(t[1].ch[i])q.push(t[1].ch[i]),t[t[1].ch[i]].fail=1;
		else t[1].ch[i]=1;
	}
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=0;i<26;i++){
			if(t[x].ch[i])t[t[x].ch[i]].fail=t[t[x].fail].ch[i],q.push(t[x].ch[i]);
			else t[x].ch[i]=t[t[x].fail].ch[i];
		}
		int y=t[x].fail;
		while(y!=1&&!t[y].state)y=t[y].fail;
		t[x].state|=t[y].state;
	}
}

就是最后几行,暴力跳到\(fail\)树中第一个有值的祖先(再往前的祖先的答案已经存在了现在这个祖先的\(state\)里)。

然后就是爆搜,从根开始,按照字典序bfs。

void bfs(){
	Q.push(node(1,0,cnt=1));
	vis[1][0]=true;
	while(!Q.empty()){
		node x=Q.front();Q.pop();
		if(x.state==MAXN-1){print(x.id);exit(0);}
		for(int i=0;i<26;i++){
			int nstate=x.state|t[t[x.pos].ch[i]].state;
			if(vis[t[x.pos].ch[i]][nstate])continue;
			vis[t[x.pos].ch[i]][nstate]=true;
			from[++cnt]=x.id;
			way[cnt]=i;
			Q.push(node(t[x.pos].ch[i],nstate,cnt));
		}
	}
}

\(node\)是一个结构体,第一维\(pos\)意为这个状态在trie中的节点编号,第二维\(state\)就是前文所述的“状态”,第三维\(id\)是它新的编号(在倒推路径时用到)。

\(vis\)数组储存各个状态有没有被访问过,这可以避免重复搜索。

\(from\)\(way\)是路径数组。

\(print()\)函数调用\(from\)\(way\)输出答案。

\((MAXN-1)\)\((2^n-1)\),即全\(1\)状态。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,cnt=1,S,from[2501000],MAXN;
char s[110],way[2501000];
bool vis[610][5010];
struct AC_Automaton{
	int ch[26],state,fail;
}t[610];
void ins(int id){
	int x=1;
	for(int i=0;i<S;i++){
		if(!t[x].ch[s[i]-'A'])t[x].ch[s[i]-'A']=++cnt;
		x=t[x].ch[s[i]-'A'];
	}
	t[x].state|=(1<<id);
}
queue<int>q;
void build(){
	for(int i=0;i<26;i++){
		if(t[1].ch[i])q.push(t[1].ch[i]),t[t[1].ch[i]].fail=1;
		else t[1].ch[i]=1;
	}
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=0;i<26;i++){
			if(t[x].ch[i])t[t[x].ch[i]].fail=t[t[x].fail].ch[i],q.push(t[x].ch[i]);
			else t[x].ch[i]=t[t[x].fail].ch[i];
		}
		int y=t[x].fail;
		while(y!=1&&!t[y].state)y=t[y].fail;
		t[x].state|=t[y].state;
	}
}
struct node{
	int pos,state,id;
	node(int x=0,int y=0,int z=0){
		pos=x,state=y,id=z;
	}
};
void print(int pos){
	if(from[pos]!=1)print(from[pos]);
	putchar(way[pos]+'A');
}
queue<node>Q;
void bfs(){
	Q.push(node(1,0,cnt=1));
	vis[1][0]=true;
	while(!Q.empty()){
		node x=Q.front();Q.pop();
		if(x.state==MAXN-1){print(x.id);exit(0);}
		for(int i=0;i<26;i++){
			int nstate=x.state|t[t[x.pos].ch[i]].state;
			if(vis[t[x.pos].ch[i]][nstate])continue;
			vis[t[x.pos].ch[i]][nstate]=true;
			from[++cnt]=x.id;
			way[cnt]=i;
			Q.push(node(t[x.pos].ch[i],nstate,cnt));
		}
	}
}
int main(){
	scanf("%d",&n),MAXN=(1<<n);
	for(int i=0;i<n;i++)scanf("%s",s),S=strlen(s),ins(i);
	build();
	bfs();
	return 0;
}
posted @ 2020-04-26 17:36  Troverld  阅读(110)  评论(0编辑  收藏  举报