bzoj 4327: JSOI2012 玄武密码
听说这题不公开.. 那就不贴题意了
一眼看上去还以为是exkmp的裸题.. 看了数据范围,呵呵..
多串匹配嘛.. 就用AC自动机咯,而且每个点最多也就只有$4$个孩子
用原串在AC自动机上走,碰到的和fail到的都是可以到达的字符串,每个点标记记录一下,这个时间复杂度是$O(n)$的
然后再每个串走AC自动机,找到最远的被标记的点就是答案了..
1 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 using namespace std; 8 const int Maxn = 100010; 9 const int Maxm = 10000010; 10 struct trie { 11 int child[4], fl, fail; 12 }tr[Maxm]; int tot, rt; 13 char s[Maxm], st[Maxn][110]; int n, stl[Maxn]; 14 int m; 15 int get ( char c ){ 16 if ( c == 'N' ) return 0; 17 if ( c == 'W' ) return 1; 18 if ( c == 'E' ) return 2; 19 return 3; 20 } 21 void bulid ( int &now, int l, int x ){ 22 if ( !now ) now = ++tot; 23 if ( l == stl[x]+1 ) return; 24 bulid ( tr[now].child[get(st[x][l])], l+1, x ); 25 } 26 void bulid_ac (){ 27 queue <int> q; 28 q.push (rt); 29 while ( !q.empty () ){ 30 int x = q.front (); q.pop (); 31 for ( int i = 0; i < 4; i ++ ){ 32 int y = tr[x].child[i]; 33 if ( !y ){ 34 if ( x == rt ) tr[x].child[i] = x; 35 else tr[x].child[i] = tr[tr[x].fail].child[i]; 36 } 37 else { 38 if ( x == rt ) tr[y].fail = x; 39 else tr[y].fail = tr[tr[x].fail].child[i]; 40 } 41 if ( y > 0 ) q.push (y); 42 } 43 } 44 } 45 int find ( int now, int l, int x ){ 46 if ( l == stl[x]+1 ) return stl[x]; 47 if ( tr[tr[now].child[get(st[x][l])]].fl == 0 ) return l-1; 48 return find ( tr[now].child[get(st[x][l])], l+1, x ); 49 } 50 int main (){ 51 int i, j, k; 52 scanf ( "%d%d", &n, &m ); 53 scanf ( "%s", s+1 ); 54 for ( i = 1; i <= m; i ++ ){ 55 scanf ( "%s", st[i]+1 ); 56 stl[i] = strlen (st[i]+1); 57 bulid ( rt, 1, i ); 58 } 59 bulid_ac (); 60 int now = rt; 61 for ( i = 1; i <= n; i ++ ){ 62 now = tr[now].child[get(s[i])]; 63 int x = now; 64 while ( tr[x].fl == 0 && x ){ 65 tr[x].fl = 1; 66 x = tr[x].fail; 67 } 68 } 69 for ( i = 1; i <= m; i ++ ){ 70 printf ( "%d\n", find ( rt, 1, i ) ); 71 } 72 return 0; 73 }
作者:Ra1nbow
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。