1. 程式人生 > 其它 >[hdu 6096 String](巧妙建圖,AC自動機)

[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]]);
    }


}