[hdu 6096 String](巧妙建图,AC自动机)

题目传送门

题意:

给n个字符串,和q个询问,每个询问给一个前缀和后缀,问你在这n个字符串中有多少个包含这一对前缀和后缀,前缀后缀不能重叠。

题解:

这题有一个巧妙的办法,用AC自动机去跑。

比如待匹配串是abc,abcd,那么我们将它们转换为abc{abc,abcd{abcd,

为什么用'{'呢,因为ascll表里面{位于z的后面,[位于Z的后面,这样比用'#'更方便。

ps:我一开始溢出了,这vscode居然不给我报错。。。。

然后询问是a c和ab cd ,那么就将询问转换为c{a和cd{ab。

然后将询问插进AC自动机,将每个带匹配串拿去匹配一下,同时注意a 匹配 a a,这里重合了,所以每次匹配要判断长度。

code:

#include<bits/stdc++.h>
using namespace std;
#define N 100003
int n,tot,qq,ans_temp[N],Ans[N],LEN[N];
string T[N];
struct trie{
	int son[29],fail,val,id;
}tr[N*51];
queue<int>Q;
void insert(){
    string S,B;

	int root=0,tot=0;
    memset(tr[0].son,0,sizeof(tr[0].son));
    tr[0].fail=tr[0].val=tr[0].id=0;
	for(int i=1;i<=qq;i++){
        ans_temp[i]=i;
        Ans[i]=0; 
    }
    for(int i=1;i<=qq;i++){
		root=0;
        cin>>S>>B;
         B=B+'{';
         B=B+S;
         S=B; 
            int lens=S.length();
		for(int p=0;p<lens;++p){
			int k=S[p]-'a';
         //   cout<<root<<"_"<<k<<endl;
			if(!tr[root].son[k]){
                memset(tr[tot+1].son,0,sizeof(tr[tot+1].son));
                tr[tot+1].fail=tr[tot+1].val=tr[tot+1].id=0;
				tr[root].son[k]=++tot;
            }
			root=tr[root].son[k];
		}
        if(!tr[root].id)
            tr[root].id=i;
        else ans_temp[i]=tr[root].id; 
        LEN[tr[root].id]=lens;
	}
}
void makefail(){
	while(!Q.empty())Q.pop();
	for(int i=0;i<27;i++){
		if(tr[0].son[i]){
			tr[tr[0].son[i]].fail=0;
			Q.push(tr[0].son[i]);
		}
	}
	while(!Q.empty()){
		int u=Q.front();
		Q.pop();
		for(int i=0;i<27;++i){
			if(tr[u].son[i]){
				tr[tr[u].son[i]].fail=tr[tr[u].fail].son[i];
				Q.push(tr[u].son[i]);
			}
			else
				tr[u].son[i]=tr[tr[u].fail].son[i];
		}
	}
}
void  query(string t){
	int le=t.length(),u=0,k;
	for(int i=0;i<le;i++)
	{
		k=t[i]-'a';u=tr[u].son[k]; 
		for(int p=u;p;p=tr[p].fail)
		{  
            if(((le-2)>>1)>=LEN[tr[p].id]-1){
		    	Ans[tr[p].id]++;
            }
		}
	}
    return ;
}
int main(){
    int Ti;
    cin>>Ti;
    while(Ti--){
	    cin>>n>>qq;
        for(int i=1;i<=n;i++)
            cin>>T[i];      
        insert();   
        makefail();  
        for(int i=1;i<=n;i++){
            T[i]=T[i]+'{';
            T[i]=T[i]+T[i]; 
            query(T[i]);
        } 
        for(int i=1;i<=qq;i++)printf("%d\n",Ans[ans_temp[i]]);
    }


}
posted @ 2021-08-11 11:40  GUO_dx  阅读(35)  评论(0编辑  收藏  举报