[coci2012]覆盖字符串 AC自动机
Posted CHADLZX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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 }
以上是关于[coci2012]覆盖字符串 AC自动机的主要内容,如果未能解决你的问题,请参考以下文章
[COCI2015] Divljak - AC自动机,DFS序,树状数组,LCA
bzoj3881[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组
BZOJ3881 Coci2015 Divljak fail树+差分