码迷,mamicode.com
首页 > 其他好文 > 详细

CSU2004:Finding words(含指定不相交前后缀的模式串计数)

时间:2020-02-28 01:33:25      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:字符   判断   span   指定   pac   题意   相同   分析   sign   

题: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\n",ans[i]);
    return 0;
}
View Code

 

CSU2004:Finding words(含指定不相交前后缀的模式串计数)

标签:字符   判断   span   指定   pac   题意   相同   分析   sign   

原文地址:https://www.cnblogs.com/starve/p/12375401.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!