ZOJ   3228

题目网址:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16401

Description

Little jay really hates to deal with string. But moondy likes it very much, and she's so mischievous that she often gives jay some dull problems related to string. And one day, moondy gave jay another problem, poor jay finally broke out and cried, " Who can help me? I'll bg him! "

So what is the problem this time?

First, moondy gave jay a very long string A. Then she gave him a sequence of very short substrings, and asked him to find how many times each substring appeared in string A. What's more, she would denote whether or not founded appearances of this substring are allowed to overlap.

At first, jay just read string A from begin to end to search all appearances of each given substring. But he soon felt exhausted and couldn't go on any more, so he gave up and broke out this time.

I know you're a good guy and will help with jay even without bg, won't you?

Input

Input consists of multiple cases( <= 20 ) and terminates with end of file.

For each case, the first line contains string A ( length <= 10^5 ). The second line contains an integer N ( N <= 10^5 ), which denotes the number of queries. The next N lines, each with an integer type and a string a ( length <= 6 ), type = 0 denotes substring a is allowed to overlap and type = 1 denotes not. Note that all input characters are lowercase.

There is a blank line between two consecutive cases.

Output

For each case, output the case number first ( based on 1 , see Samples ).

Then for each query, output an integer in a single line denoting the maximum times you can find the substring under certain rules.

Output an empty line after each case.

Sample Input

ab
2
0 ab
1 ab abababac
2
0 aba
1 aba abcdefghijklmnopqrstuvwxyz
3
0 abc
1 def
1 jmn

Sample Output

Case 1
1
1 Case 2
3
2 Case 3
1
1
0

Hint

In Case 2,you can find the first substring starting in position (indexed from 0) 0,2,4, since they're allowed to overlap. The second substring starts in position 0 and 4, since they're not allowed to overlap.

For C++ users, kindly use scanf to avoid TLE for huge inputs.

题意:给了N个模式串,然后又给了一个长串,求每个模式串在这个长串中出现的次数。每个模式串前给了类型限制,若为0,表示串可以重叠,1表示不能重叠。

思路:当为0类型时,可以重叠,则和以前的AC自动机模板一样,1时,需要在模式串的最后一个字符的结构体内标识一下上一次这个串在长串中出现的位置,当再次匹配到这个串的末尾时,用当前串的位置序号减去上次出现的位置序号,若长大于等于模式串的长度,则串出现次数加一。注意:相同的串并且是相同类型的串可能出现多次,如 0 aba ,0 aba

所以可以在字符结构体中记录0型和1型串出现次数,记录输入的模式串,最后按顺序输出时,将对应的串和类型数传到trie树中查找,返回输出记录0型和1型串出现的次数。

参考别人的代码如下:

#include <stdio.h>
#include <string.h>
#include <memory.h>
struct node{
node *fail;
node *next[];
int id;
node(){
fail=NULL;
id=;
memset(next,NULL,sizeof(next));
}
}*q[],*root;
int head,tail;
char str1[][],str2[];
int A[],cnt[][],pos[],Len[],n;
void insert_Trie(char *str,int num1){
node *p=root;
int i=,id;
while(str[i]){
id=str[i]-'a';
if(p->next[id]==NULL) p->next[id]=new node();
p=p->next[id];i++;
}
p->id=num1;
}
int search_1(char *str){
node *p=root;
int m,i=;
while(str[i]){
m=str[i]-'a';
if(p->next[m]==NULL) return -;
p=p->next[m];
i++;
}
return p->id;
}
void setfail() ///初始化fail指针,BFS
{
q[tail++]=root;
while(head!=tail)
{
node *p=q[head++];
node *temp=NULL;
for(int i=;i<;i++)
if(p->next[i]!=NULL)
{
if(p==root) ///首字母的fail必指向根
p->next[i]->fail=root;
else
{
temp=p->fail; ///失败指针
while(temp!=NULL) ///2种情况结束:匹配为空or找到匹配
{
if(temp->next[i]!=NULL) ///找到匹配
{
p->next[i]->fail=temp->next[i];
break;
}
temp=temp->fail;
}
if(temp==NULL) ///为空则从头匹配
p->next[i]->fail=root;
}
q[tail++]=p->next[i]; ///入队
}
}
} void query(){
int i=;
node *p=root,*temp;
while(str2[i]){
int id=str2[i]-'a';
while(p->next[id]==NULL&&p!=root) p=p->fail;
p=p->next[id];
p=(p==NULL)?root:p;
temp=p;
while(temp!=root){
if(temp->id){
cnt[temp->id][]++;
}
temp=temp->fail;
}
i++;
}
}
void query1(){
int i=;
node *p=root,*temp;
while(str2[i]){
int id=str2[i]-'a';
while(p->next[id]==NULL&&p!=root) p=p->fail;
p=p->next[id];
p=(p==NULL)?root:p;
temp=p;
while(temp!=root){
if(temp->id&&i-pos[temp->id]>=Len[temp->id]){
pos[temp->id]=i;
cnt[temp->id][]++;
}
temp=temp->fail;
}
i++;
}
}
int query_num(char *str,int aa){
int i=;
node *p=root;
while(str[i]){
int id=str[i]-'a';
p=p->next[id];
i++;
}
return cnt[p->id][aa];
}
void del(node *p){
if(p==NULL)return ;
for(int i=;i<;i++)del(p->next[i]);
delete p;
}
int main(){
int t=;
while(scanf("%s",str2)!=-){
scanf("%d",&n);
head=;
tail=;
root=new node();
memset(cnt,,sizeof(cnt));
memset(pos,-,sizeof(pos));
for(int i=;i<=n;i++){
scanf("%d%s",&A[i],str1[i]);
Len[i]=strlen(str1[i]);
insert_Trie(str1[i],i);
}
setfail();
query();
query1();
printf("Case %d\n",t++);
for(int i=;i<=n;i++){
int ttt=query_num(str1[i],A[i]);
printf("%d\n",ttt);
}
printf("\n");
del(root);
}
return ;
}

我的代码如下:(我写的代码很清晰,各种样例都测试通过了,但提交就是wa,唉~)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 770010
char str[],keyword[][];
int head,tail,key[]; struct node
{
node *fail;
node *next[];
int f;
int count1;
int count2;
int b,l;
node()
{
fail=NULL;
count1=;
count2=;
f=-;
b=;
l=;
for(int i=;i<;i++)
next[i]=NULL;
}
}*q[N];
node *root; int insert(char *str,int x) ///建立Trie
{
int temp,len;
node *p=root;
len=strlen(str);
for(int i=;i<len;i++)
{
temp=str[i]-'a';
if(p->next[temp]==NULL)
p->next[temp]=new node();
p=p->next[temp];
}
p->f++;
p->l=len;
if(!x) return p->count1;
else return p->count2;
} void setfail() ///初始化fail指针,BFS
{
q[tail++]=root;
while(head!=tail)
{
node *p=q[head++];
node *temp=NULL;
for(int i=;i<;i++)
if(p->next[i]!=NULL)
{
if(p==root) ///首字母的fail必指向根
p->next[i]->fail=root;
else
{
temp=p->fail; ///失败指针
while(temp!=NULL) ///2种情况结束:匹配为空or找到匹配
{
if(temp->next[i]!=NULL) ///找到匹配
{
p->next[i]->fail=temp->next[i];
break;
}
temp=temp->fail;
}
if(temp==NULL) ///为空则从头匹配
p->next[i]->fail=root;
}
q[tail++]=p->next[i]; ///入队
}
}
} void query()
{
int index,len;
node *p=root;
len=strlen(str);
for(int i=;i<len;i++)
{
index=str[i]- 'a';
while(p->next[index]==NULL&&p!=root) ///跳转失败指针
p=p->fail;
p=p->next[index];
if(p==NULL)
p=root;
node *temp=p; ///p不动,temp计算后缀串
while(temp!=root&&temp->f!=-)
{
temp->count1++;
if(temp->b==||(i-temp->b)>=(temp->l))
{
temp->count2++;
temp->b=i;
}
temp=temp->fail;
}
}
}
void free_(node *r)
{
for(int i=; i<; i++)
{
if(r->next[i])
free_(r->next[i]);
}
free(r);
} int main()
{
int num,Case=;
while(~scanf("%s",str))
{
head=tail=;
memset(key,,sizeof(key));
root = new node();
scanf("%d", &num);
for(int i=;i<=num;i++)
{
scanf("%d %s",&key[i],keyword[i]);
insert(keyword[i],i);
}
setfail();
query();
printf("Case %d\n",Case++);
for(int i=;i<=num;i++)
{
printf("%d\n",insert(keyword[i],key[i]));
}
printf("\n");
free_(root);
}
return ;
}

AC自动机---Searching the String的更多相关文章

  1. ZOJ 3228 Searching the String(AC自动机)

    Searching the String Time Limit: 7 Seconds      Memory Limit: 129872 KB Little jay really hates to d ...

  2. zoj3228 Searching the String AC自动机查询目标串中模式串出现次数(分可覆盖,不可覆盖两种情况)

    /** 题目:zoj3228 Searching the String 链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=34 ...

  3. ZOJ3228 Searching the String —— AC自动机 + 可重叠/不可重叠

    题目链接:https://vjudge.net/problem/ZOJ-3228 Searching the String Time Limit: 7 Seconds      Memory Limi ...

  4. ZOJ3228 Searching the String (AC自动机)

    Searching the String Time Limit: 7 Seconds                                      Memory Limit: 129872 ...

  5. 【ZOJ 3228】Searching the String 【AC自动机】

    题意 给出n个模式串和一个文本串,输出各个模式串在文本串中出现的次数.模式串有两种类型,0类型代表可以有重叠,1类型代表不能有重叠.模式串可能出现重复. 分析 算是AC自动机的模板题? 因为模式串可以 ...

  6. Searching the String ZOJ - 3228 AC自动机查询升级版

    题意:先给你一个不超过1000000长度的大串s:接下来输入一个n代表接下来输入的小串个数,小串长度不超过6. 小串分两种类型0和1类型. 0类型表示小串在大串中的最大匹配个数就是常规的AC自动机的做 ...

  7. ZOJ3228 - Searching the String(AC自动机)

    题目大意 给定一个文本串,接下来有n个模式串,每次查询模式串出现的次数,查询分两种,可重叠和不可重叠 题解 第一次是把AC自动机构造好,跑n次,统计出每个模式串出现的次数,交上去果断TLE...后来想 ...

  8. 【AC自动机】zoj3228 Searching the String

    对所有模式串建立AC自动机. 每个单词结点要记录该单词长度. 然后在跑匹配的时候,对每个单词结点再处理3个值,代表可重叠的匹配次数,不可重叠的匹配次数,以及“上一次不可重叠的匹配位置”,这样结合单词长 ...

  9. 【Codeforces710F】String Set Queries (强制在线)AC自动机 + 二进制分组

    F. String Set Queries time limit per test:3 seconds memory limit per test:768 megabytes input:standa ...

随机推荐

  1. Android客户端与PHP服务端交互(一)---框架概述

    背景 作为一个普通上班族,总是想做一些自认为有意义的事情,于是乎准备成立一个工作室,尽管目前正在筹备阶段,但是之前有些朋友提出一些需求的时候,我发现自己的能力还是有限,直到最近和一些技术牛朋友聊起这事 ...

  2. 哈夫曼算法(haffman)实现压缩和解压缩-C语言实现

    /* * ===================================================================================== * * Filen ...

  3. 导出程序界面(UI)到图片

    无意间看到这个需求,查阅了相关文章,有两篇不错的博客给出了解决方案,地址如下: 1.在WPF程序中将控件所呈现的内容保存成图像 2.随心所欲导出你的 UI 界面到 PDF 文件 主要使用的接口: Si ...

  4. Shell之数学计算

    本博客已经迁往http://www.kemaswill.com/, 博客园这边也会继续更新, 欢迎关注~ 数学计算是Shell中比较常用的一种操作,  但是因为shell中所有的变量都默认为字符串, ...

  5. 细数Qt开发的各种坑(欢迎围观)

    1:Qt的版本多到你数都数不清,多到你开始怀疑人生.从4.6开始到5.8,从MSVC编译器到MINGW编译器,从32位到64位,从Windows到Linux到MAC.MSVC版本还必须安装对应的VS2 ...

  6. 【转】ContextMenuStrip菜单应用

    测试可用的代码: #region 右键快捷菜单单击事件 private void contextMenuStrip1_ItemClick(object sender, EventArgs e) { T ...

  7. vmware虚拟机工具vmware tools介绍及安装排错

    VMware Tools是VMware虚拟机中自带的一种增强工具,相当于VirtualBox中的增强功能(Sun VirtualBox Guest Additions),是VMware提供的增强虚拟显 ...

  8. 线程安全集合 ConcurrentDictionary<TKey, TValue> 类

    ConcurrentDictionary<TKey, TValue> 类 [表示可由多个线程同时访问的键/值对的线程安全集合.] 支持 .NET Framework 4.0 及以上. 示例 ...

  9. 解决 Tomcat 无法绑定 80 端口的问题,以及 Tomcat 配置虚拟目录、二级域名等

    问题 今天安装完 Tomcat,安装时把 Tomcat 默认的 HTTP/1.1 Connector Port 从 8080 改为了 7080,启动 Tomcat,在浏览器中输入 Http://loc ...

  10. 【原创】C#搭建足球赛事资料库与预测平台(2) 数据库与XCode组件

            本博客所有文章分类的总目录:[总目录]本博客博文总目录-实时更新 开源C#彩票数据资料库系列文章总目录:[目录]C#搭建足球赛事资料库与预测平台与彩票数据分析目录  本篇文章开始将逐步 ...