[coci2012]覆盖字符串 AC自动机

给出一个长度为N的小写字母串,现在Mirko有M个若干长度为Li字符串。现在Mirko要用这M个字符串去覆盖给出的那个字符串的。覆盖时,必须保证:
1.Mirko的字符串不能拆开,旋转;
2.Mirko的字符串必须和给出的字符串的某一连续段完全一致才能覆盖,
3.若干次覆盖可以部分重叠
4.Mirko的字符串可以无限使用。
求给出的字符串当中,有多少个字母是无法覆盖的。

小朋友们,作为一名长者,我认为我有必要向你们传授一些人生的经验~;

字符串的一堆函数,慎用慎用;

本人只因没有仔细认真,把strlen(s),strlen(ch)之类的函数写在了循环的里面,造成了无限TLE的惨剧;

图如下:

两个strlen在里面的时候:

#01: Accepted (15ms, 322696KB)
#02: Accepted (15ms, 322696KB)
#03: Accepted (187ms, 322696KB)
#04: Accepted (3234ms, 322696KB)
#05: Accepted (3453ms, 322624KB)
#06: Time Limit Exceeded (?, 322624KB)
#07: Time Limit Exceeded (?, 322624KB)
#08: Time Limit Exceeded (?, 322624KB)
#09: Time Limit Exceeded (?, 322624KB)
#10: Time Limit Exceeded (?, 322624KB)
#11: Time Limit Exceeded (?, 322624KB)
#12: Wrong Answer (5000ms, 322624KB)
#13: Wrong Answer (5000ms, 322624KB)
#14: Time Limit Exceeded (?, 322624KB)
#15: Time Limit Exceeded (?, 322624KB)
#16: Time Limit Exceeded (?, 322624KB)
#17: Wrong Answer (5000ms, 322624KB)
#18: Wrong Answer (5000ms, 322624KB)
#19: Time Limit Exceeded (?, 322624KB)

不知道的会以为我暴力枚举;

一个strlen在循环里的时候:

#01: Accepted (15ms, 345056KB)
#02: Accepted (0ms, 345056KB)
#03: Accepted (0ms, 345056KB)
#04: Accepted (218ms, 345056KB)
#05: Accepted (78ms, 345056KB)
#06: Accepted (93ms, 345056KB)
#07: Accepted (46ms, 345056KB)
#08: Accepted (1656ms, 345056KB)
#09: Time Limit Exceeded (?, 345056KB)
#10: Accepted (93ms, 344984KB)
#11: Accepted (125ms, 344984KB)
#12: Accepted (1562ms, 344984KB)
#13: Time Limit Exceeded (?, 344984KB)
#14: Accepted (171ms, 344984KB)
#15: Accepted (500ms, 344984KB)
#16: Accepted (1640ms, 344984KB)
#17: Wrong Answer (5000ms, 344984KB)
#18: Accepted (250ms, 344984KB)
#19: Accepted (734ms, 344984KB)

还是有三组超了;

没有strlen在里面的时候:

#01: Accepted (0ms, 357712KB)
#02: Accepted (0ms, 357712KB)
#03: Accepted (15ms, 357712KB)
#04: Accepted (78ms, 357712KB)
#05: Accepted (93ms, 357712KB)
#06: Accepted (46ms, 357712KB)
#07: Accepted (46ms, 357712KB)
#08: Accepted (375ms, 357712KB)
#09: Accepted (187ms, 357712KB)
#10: Accepted (93ms, 357712KB)
#11: Accepted (31ms, 357712KB)
#12: Accepted (359ms, 357712KB)
#13: Accepted (328ms, 357712KB)
#14: Accepted (187ms, 357712KB)
#15: Accepted (125ms, 357712KB)
#16: Accepted (359ms, 357712KB)
#17: Accepted (468ms, 357712KB)
#18: Accepted (281ms, 357712KB)
#19: Accepted (140ms, 357712KB)

敲完这道题,我热泪盈眶啊;

同时,我通过这道题敲了好几遍AC自动机模板;

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cstdlib>
 6 #include<ctime>
 7 #include<vector>
 8 #include<algorithm>
 9 #include<queue>
10 #include<map>
11 using namespace std;
12 #define LL long long
13 const int maxn=2500010;
14 int n,m;
15 char s[303000],ch[5050];
16 bool vis[27][27][27][27][27];
17 int linkk[1000000][27],flag[maxn],f[maxn],q[maxn],g[maxn],k[maxn],tail=0,head=1,len=0,next[maxn];
18 void insert(){
19     int now=0,p=strlen(ch);
20     for(int i=0;i<p;i++){
21         if(!linkk[now][ch[i]])linkk[now][ch[i]]=++len,g[len]=ch[i];
22         now=linkk[now][ch[i]];
23         if(i==p-1)flag[now]=p;
24     }
25 }
26 void init(){
27     //printf("first:%d\n",clock());
28     scanf("%d%s%d",&n,s,&m);
29     for(int i=0;i<n;i++)s[i]=s[i]-‘a‘+1;
30     for(int i=4;i<n;i++)vis[s[i-4]][s[i-3]][s[i-2]][s[i-1]][s[i]]=1;
31     //printf("second:%d\n",clock());
32     for(int i=1;i<=m;i++){
33         scanf("%s",ch);
34         bool p=0;
35         int u=strlen(ch);
36         for(int j=0;j<u;j++)ch[j]=ch[j]-‘a‘+1;
37         for(int j=4;j<u;j++)
38             if(!vis[ch[j-4]][ch[j-3]][ch[j-2]][ch[j-1]][ch[j]]){p=1;break;}
39         if(!p)insert();
40     }
41     //printf("init:%d\n",clock());
42 }
43 void bfs(){
44     head=0,tail=0;q[++tail]=0;int x=0,now=0,temp;
45     while(++head<=tail){
46         x=q[head];
47         for(int i=1;i<=26;i++){
48             if(linkk[x][i]){
49                 now=linkk[x][i],temp=f[x];
50                 if(x){
51                     while(temp&&!linkk[temp][i])temp=f[temp];
52                     f[now]=linkk[temp][i];
53                     if(flag[f[now]])next[now]=f[now];
54                     else next[now]=next[f[now]];
55                 }
56                 q[++tail]=now;
57             }
58         }
59     }
60 }
61 void work(){
62     bfs();
63     //printf("bfs:%d\n",clock());
64     int now=0;
65     for(int i=0;i<n;i++){
66         if(!linkk[now][s[i]]){
67             int temp=f[now];
68             while(!linkk[temp][s[i]]&&temp)temp=f[temp];
69             now=linkk[temp][s[i]];
70         }
71         else now=linkk[now][s[i]];
72         int temp=now;
73         while(temp){
74             if(flag[temp])k[i-flag[temp]+1]=flag[temp];
75             temp=next[temp];
76         }
77     }
78     //printf("work:%d\n",clock());
79     int last=-1,sum=0;
80     for(int i=0;i<n;i++){
81         if(k[i])last=max(last,k[i]+i-1);
82         if(i>last)sum++;
83     }
84     cout<<sum<<endl;
85     //cout<<clock()<<endl;
86 }
87 int main(){
88     freopen("1.in","r",stdin);
89     freopen("1.out","w",stdout);
90     init();
91     work();
92 }

时间: 2024-10-18 23:04:34

[coci2012]覆盖字符串 AC自动机的相关文章

JZYZOJ1369 [coci2012]覆盖字符串 AC自动机

http://172.20.6.3/Problem_Show.asp?id=1369 trie树如果不优化就这么往里面放这么多单词肯定超空间+超时,所以需要去掉无用的字符串(不属于原字符串的),但是一个一个判断时间又很长: 所以解决方案就是用一个多维vis数组胡搞判定一下,非常魔性... 代码 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5

【bzoj3172】: [Tjoi2013]单词 字符串-AC自动机

[bzoj3172]: [Tjoi2013]单词 先用所有单词构造一个AC自动机 题目要求的是每个单词在这个AC自动机里匹配到的次数 每次insert一个单词的时候把路径上的cnt++ 那么点p->cnt就是以root到p这条路径为前缀的单词的个数 如果p->fail指向了点q,那么就会对q点产生p->cnt的贡献(root到q一定为root到p的后缀) 最后递推统计完所有fail的贡献,找到关键点输出就可以了 1 /* http://www.cnblogs.com/karl07/ */

【bzoj1030】: [JSOI2007]文本生成器 字符串-AC自动机-DP

[bzoj1030]: [JSOI2007]文本生成器 首先把匹配任意一个的个数的问题转化为总个数-没有一个匹配的个数 先构造AC自动机,然后枚举每一位的字母以及在自动机上的位置 f[i][j]为第i位在j的位置且没有匹配过任何一个串的个数 然后26^m-sum(f[m][j])就是答案 还有就是当p->fail一直到root的路径上只要有一个点是一个串的终点那么点f[i][p]就要ban掉 因为这个WA了好多次 1 /* http://www.cnblogs.com/karl07/ */ 2

字符串——AC自动机

目录 一.前言 二.思路 三.代码 四.参考资料 一.前言 以前一直没学AC自动机,主要是被名字吓到了,自动AC,这么强的名字肯定很难,学了后才发现,其实不难. AC自动机并不是Acept automaton,而是Aho-Corasick automaton,A和C分别取自其发明者的姓名,有点巧. 那么,它是干什么的呢? 简而言之,是在文本串中寻找多个模板串的算法. 是不是类似于KMP算法? KMP算法是在文本串中寻找一个模板串,那么,如果用KMP解决AC自动机的题,其时间复杂度是多少呢? O(

【bzoj2434】: [Noi2011]阿狸的打字机 字符串-AC自动机-BIT

[bzoj2434]: [Noi2011]阿狸的打字机 x串在y串上的匹配次数就是y在自动机所有节点上能够通过fail走到x最后一个节点的个数 (就是y串任意一个前缀的后缀能匹配到x的个数)和[bzoj3172]: [Tjoi2013]单词差不多 把fail指针反向就是x的子树的和 用dfs序+BIT就可以维护了 如果把y串一个个走自动机显然会TLE 但是如果按照打字顺序模拟'a'-'z' 在trie上前进一格单点+1 'B'在trie上后退一格单点-1 那么显然可以得到所有y串但只需要O(n)

多模字符串匹配算法之AC自动机—原理与实现

简介: 本文是博主自身对AC自动机的原理的一些理解和看法,主要以举例的方式讲解,同时又配以相应的图片.代码实现部分也予以明确的注释,希望给大家不一样的感受.AC自动机主要用于多模式字符串的匹配,本质上是KMP算法的树形扩展.这篇文章主要介绍AC自动机的工作原理,并在此基础上用Java代码实现一个简易的AC自动机. 欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. 应用场景-多模字符串匹配 我们现在考虑这样一个问题,在一个文本串t

hdu 2296 aC自动机+dp(得到价值最大的字符串)

Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3180    Accepted Submission(s): 1033 Problem Description For the hope of a forever love, Steven is planning to send a ring to Jane with a rom

字符串(AC自动机):HDU 5129 Yong Zheng&#39;s Death

Yong Zheng's Death Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)Total Submission(s): 224    Accepted Submission(s): 37 Problem Description Some Chinese emperors ended up with a mysterious death. Many historia

高效处理字符串!——AC自动机

AC自动机 这两天进军AC自动机算法,越做越觉得这种算法的灵活与高效,接下来对这阵子的学习做个总结. AC自动机,当然它最主要的作用是自动帮你AC题目多模式串的匹配,也就是字典树trie和kmp的结合,再深入讲就是把kmp中失配时跳转的思想运用到trie上! 1.AC自动机构建 对于构建,基本上都是模板,先建trie,再BFS这颗trie从而构建出最重要的fail指针,即失配跳转指针(口头表达),fail指针指向的是当前状态的最长后继.         而一般我们为了加快速度,每个节点还会构建类