zoukankan      html  css  js  c++  java
  • CSU2004:Finding words(含指定不相交前后缀的模式串计数)

    题:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2004

    题意:给定n个模式串,m个询问,每个询问是“前缀+‘*’+后缀 ”的组合的串S,输出n个模式串中有几个和S是相同的,‘*’可以是0和或更多的字符组成

    分析:一般是用给定的模式串来减trie图,但这题显然比较困难,解不出,那么就考虑反过来,我们拿询问的字符串进行构建;

       这里要做一下处理:以“后缀+’z+1‘+前缀”地插入trie图,z+1用来代替特殊字符;

       因为题目要求的是类似断开的询问串,而我们可以想象一下询问串的首位相连的话,同时将n个模式串首尾链接的话,前缀和后缀就连在一起了且具有唯一性,所以只要我们只要以模式串来跑trie图就行了;

       n个模式串的首尾相连根据trie的处理来,就是直接s+’z+1‘+s即可;  

       至于为啥要用’z+1‘来+在首尾相连的地方,因为如果不加的话,可能这样处理会创造出新的原本不存在的序列出来;

       注意,在跑ac自动机的时候要判断长度是否满足条件,因为我们这里相当于把n个模式串扩大了俩倍+1,而查询串的长度不变。

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int M=1e6+5;
    const int N=1e5+5;
    const int maxn=27;
    int ans[N];
    struct ac{
        int trie[M][maxn],end[M],fail[M],Len[M];
        int root,tot;
        int newnode(){
            for(int i=0;i<maxn;i++){
                trie[tot][i]=-1;
            }
            end[tot++]=0;
            return tot-1;
        }
        void init(){
            tot=0;
            root=newnode();
        }
        void insert(string buf,int id){
            int len=buf.size();
            int now=root;
            for(int i=0;i<len;i++){
                if(trie[now][buf[i]-'a']==-1)
                    trie[now][buf[i]-'a']=newnode();
                now=trie[now][buf[i]-'a'];
            }
            end[now]=id;
            Len[now]=len-1;
        }
        void getfail(){
            queue<int>que;
            while(!que.empty()){
                que.pop();
            }
            fail[root]=root;
            for(int i=0;i<maxn;i++){
                if(trie[root][i]==-1)
                    trie[root][i]=root;
                else{
                    fail[trie[root][i]]=root;
                    que.push(trie[root][i]);
                }
            }
            while(!que.empty()){
                int now=que.front();
                que.pop();
                for(int i=0;i<maxn;i++){
                    if(trie[now][i]!=-1){
                        fail[trie[now][i]]=trie[fail[now]][i];
                        que.push(trie[now][i]);
                    }
                    else
                        trie[now][i]=trie[fail[now]][i];
                }
            }
        }
        void query(string buf){
            int len=buf.size();
            int now=root;
            int flag=(len-1)/2;
            for(int i=0;i<len;i++){
                now=trie[now][buf[i]-'a'];
                int tmp=now;
                while(tmp!=root){
                    if(Len[tmp]&&end[tmp]!=0&&flag>=Len[tmp])
                        ans[end[tmp]]++;
                    tmp=fail[tmp];
                }
            }
        }
    }AC;
    char sign='z'+1;
    string s[M];
    char buf[33];
    int main(){
    
        AC.init();
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",buf);
            s[i]=buf;
            s[i]=s[i]+sign+s[i];
        }
        int m;
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%s",buf);
            string s2=buf;
            if(s2=="*"){
                ans[i]=n;
                continue;
            }
            int j; 
            for(j=0;j<s2.size();j++){
                if(s2[j]=='*')
                    break;
            }
            s2=s2.substr(j+1,s2.size()-j-1)+sign+s2.substr(0,j);
            AC.insert(s2,i);
        }
        AC.getfail();
        //cout<<"!!"<<endl;
        for(int i=1;i<=n;i++){
            AC.query(s[i]); 
        }
        for(int i=1;i<=m;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    SQL Server 2008 导出数据与导入数据任务介绍
    如何绕过chrome的弹窗拦截机制
    jquery操作select(增加,删除,清空)
    JSON详解
    Intellij+Spring学习(一)
    Intellij IEDA 14.0+Tomcat Servlet开发
    04-Spring的注解开发
    03-Spring的XML配置
    02-Spring与IOC
    01-Spring概述
  • 原文地址:https://www.cnblogs.com/starve/p/12375401.html
Copyright © 2011-2022 走看看