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

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

时间: 2024-08-02 00:06:16

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

Hibernate给表和字段设置前后缀及分隔符

在<一口一口吃掉Hibernate(一)--使用SchemaExport生成数据表>中介绍了如何生成数据表.但是这只是最基本的.hibernate在生成或者操作数据库时,会受一些限制.比如一开始设计表的时候,直接写成了user(id,name,password,createTime)  这种格式的.但是客户后来要求表名称要以"t_"开头,字段名要以"stu_"开头,可以是一些数据库的关键字,单词之间以"_"隔开,方便他们维护.例如:T

黑马程序员---OC基础9【Foundation框架】【NSString介绍】【NSURL读写字符串】【NSString字符串比较】【NSString前后缀检查及搜索】【NSRange使用】

------- iOS培训.Android培训.Java培训.期待与您交流! ---------- [Foundation框架] 1.Foundation框架介绍 1)Foundation框架概念 框架是由许多类.方法.函数.文档按照一定的逻辑组织起来的集合 以便使研发程序变得 更容易在OS X下的Mac操作系统中大约有80个框架为所有程序开发奠定基础的框架称为Foundation 框架 2)Foundation框架的作用 Foundation框架是Mac\iOS中其他框架的基础 Foundat

HDU - 6096 :String (AC自动机,已知前后缀,匹配单词,弱数据)

Bob has a dictionary with N words in it. Now there is a list of words in which the middle part of the word has continuous letters disappeared. The middle part does not include the first and last character. We only know the prefix and suffix of each w

Debian下自动备份文件并上传到远程FTP服务器且删除指定日期前的备份Shell脚本

说明:  1.备份目录/home/osyunwei下面所有的文件到/home/osyunweibak里面,并且保存为osyunwei20120701.tar.gz的压缩文件格式(2012_07_01是指备份执行时当天的日期),最后只保留最近7天的备份 2.上传/home/osyunweibak里面的备份文件到远程FTP服务器上,并且只保留最近7天的备份. 3.FTP服务器:192.168.21.139 端口:21 账号:osyunwei 密码:123456 osyunweibak为备份文件存放目

Linux下定时切割Mongodb数据库日志并删除指定天数前的日志记录(转)

文章转自:http://www.osyunwei.com/archives/8998.html 说明: 操作系统:CentOS Mongodb安装目录:/usr/local/mongodb Mongodb数据库存放目录:/home/data/mongodb/mongodb_data Mongodb日志存放目录:/home/data/mongodb/mongodb_log 实现目的: 对Mongodb数据库日志按天保存,并且只保留最近7天的日志记录. 具体操作: 使用Mongodb数据库自带的命令

#415 Div2 Problem C Do you want a data? (math &amp;&amp; 前后缀和 &amp;&amp; 快速幂)

题意: 首先定义集合的F值为  这个集合里面最大值和最小值的差. 现给出一个拥有n个数的集合(没有相同的元素), 要求求出这个集合内所有子集的F的值的和.例如: {4.7}这个集合里面有子集{4}.{7}.{4, 7}, 则这些子集的F值分别为4-4=0.7-7=0.7-4=3, 所以最后的结果就是0+0+3 = 3! 以下分析引用至 : http://blog.csdn.net/dragon60066/article/details/72599167 分析: 不难想到要先使数组升序方便计算和思

poj 2752 求一个字符串所有的相同前后缀

求一个字符串所有的相同前后缀Sample Input ababcababababcababaaaaaSample Output 2 4 9 181 2 3 4 5 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <stack> 5 using namespace std; 6 7 const int N = 400010; 8 int next[N]; 9 c

涛哥的Python工具箱之批量删除含指定字符串行

我们在软件研发中不可避免的要用到大量的反复性的繁琐的工作,比如批量改动代码中接口的字符串.批量下载文件并又一次按规则命名.这些工作人工做特别累,尤其是对我这样的懒人来说. 对于一个出色的程序猿来说,反复是最不能接受的事情之中的一个,因此我们要发明工具把反复的工作自己主动化.曾经我是用linux shell脚本来完毕这些事情的,但因为shell脚本语法能力的限制.有些复杂功能无法有效高速的实现,而且写出的代码难以维护,基本属于一次性代码,非常难复用.因此后面慢慢開始尝试用Python完毕一些自己主

【kmp+求所有公共前后缀长度】poj 2752 Seek the Name, Seek the Fame

http://poj.org/problem?id=2752 [题意] 给定一个字符串,求这个字符串的所有公共前后缀的长度,按从小到达输出 [思路] 利用kmp的next数组,最后加上这个字符串本身 [AC] 1 #include<iostream> 2 #include<cstring> 3 #include<string> 4 #include<cstdio> 5 #include<algorithm> 6 using namespace s