zoukankan      html  css  js  c++  java
  • [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
    ",Ans[ans_temp[i]]);
        }
    
    
    }
    
  • 相关阅读:
    这段时间的总结以及未来一个月的计划
    通过配置文件构建XML
    利用汇编实现表驱动
    Intel汇编语言程序设计课后习题,6.5.5
    盲目地相信网上评价未必是好事
    ObjectiveC基础语法复习笔记
    IOS6.0 学习第1篇,基础的IOs框架
    IOS6.0 学习第2篇,弹出AlertView
    Android Fragment的使用(1)
    ObjecteiveC 属性修饰符
  • 原文地址:https://www.cnblogs.com/GUOGaby/p/15127542.html
Copyright © 2011-2022 走看看