• [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;
    }
    
  • 相关阅读:
    python基础-递归
    python基础-三元表达式/列表推导式/生成器表达式
    python基础-生成器
    python基础-迭代器
    python基础-函数
    python基础-文件操作
    Docker(六)安装Red5进行rtmp推流
    Docker(五)安装Fastdfs
    Docker(四)安装Redis
    Docker(三)安装Mysql
  • 原文地址:https://www.cnblogs.com/Troverld/p/12781124.html
Copyright © 2020-2023  润新知