3.3 字符串(1)

Trie 前缀树 字典树  

例题11  LA 3942 http://acm.hust.edu.cn/vjudge/problem/22109

字典树第一个例题我用set水过,先记录这个版本吧,题意是,给一个串,还有一些短串的集合,问有多少种不同的拆分方法使得拆分完后,每个子串都在集合中。

dp[len] 表示前len个有多少拆分法 dp[0]=1, 前0个字符有一种拆分法,空嘛。  dp[len] 就是答案,  转移就是, 如果接下来一段在集合中,那么就可以转移到长度加这段的长度。

 

起点有la=3e5,,对每一个起点,加的串可能有lbi=100,都要枚举,接下来就是判断这个串是否存在,用hash值判,o1,set查询logn ,n=4000, 总体复杂度 la*lb*logn 飘过2700ms。

 

 1 //#define txtout
 2 //#define debug
 3 #include<bits/stdc++.h>
 4 #define mt(a,b) memset(a,b,sizeof(a))
 5 using namespace std;
 6 typedef long long LL;
 7 const double pi=acos(-1.0);
 8 const double eps=1e-8;
 9 const int inf=0x3f3f3f3f;
10 const int M=3e5+10;
11 const LL MOD=20071027;
12 class String_Hash {///字符串哈希 init O(n) query O(1)
13     typedef unsigned long long typec;///hash 值类型
14     static const int MV=3e5+10;///串长度
15     static const int key=137;///hash 种子值选素数好
16     typec H[MV],xp[MV];
17 public:
18     void init(char s[],int ls) { ///传入串数组和串长
19         H[ls]=0;
20         for(int i=ls-1; i>=0; i--) {
21             H[i]=H[i+1]*key+s[i];
22         }
23         xp[0]=1;
24         for(int i=1; i<=ls; i++) {
25             xp[i]=xp[i-1]*key;
26         }
27     }
28     typec get(int pos,int len) { ///传入初始位置 pos,串长 len,返回串 hash 值
29         return H[pos]-H[pos+len]*xp[len];
30     }
31 }Hash;
32 int n;
33 char a[M];
34 char b[4010][110];
35 LL dp[M];
36 set<unsigned long long> s;
37 int max_len;
38 void init_set() {
39     s.clear();
40     max_len=0;
41     for(int i=0; i<n; i++) {
42         int lb=strlen(b[i]);
43         Hash.init(b[i],lb);
44         s.insert(Hash.get(0,lb));
45         max_len=max(max_len,lb);
46     }
47 }
48 LL solve() {
49     init_set();
50     int len=strlen(a);
51     for(int i=0; i<=len; i++) {
52         dp[i]=0;
53     }
54     dp[0]=1;
55     Hash.init(a,strlen(a));
56     for(int i=0; i<len; i++) {
57         if(dp[i]==0) continue;
58         for(int j=0; j<max_len; j++) {
59             if(!s.count(Hash.get(i,j+1))) continue;
60             dp[i+j+1]+=dp[i];
61             dp[i+j+1]%=MOD;
62         }
63     }
64     return dp[len];
65 }
66 int main() {
67 #ifdef txtout
68     freopen("in.txt","r",stdin);
69     freopen("out.txt","w",stdout);
70 #endif // txtout
71     int cas=1;
72     while(~scanf("%s%d",a,&n)) {
73         for(int i=0; i<n; i++) {
74             scanf("%s",b[i]);
75         }
76         printf("Case %d: %lld\n",cas++,solve());
77     }
78     return 0;
79 }
View Code

 

 字典树特别快72ms.  与上一种方法的差别就在于,用字典树存小串集合,然后还是枚举起点, 更新的时候就在字典树里更新, 遇到一个串就更新一个dp, 最坏情况复杂度 la*lb.

 

  1 //#define txtout
  2 //#define debug
  3 #include<bits/stdc++.h>
  4 #define mt(a,b) memset(a,b,sizeof(a))
  5 using namespace std;
  6 typedef long long LL;
  7 const double pi=acos(-1.0);
  8 const double eps=1e-8;
  9 const int inf=0x3f3f3f3f;
 10 const int M=3e5+10;
 11 const LL MOD=20071027;
 12 class Trie_tree {   //字典树  前缀树
 13     struct node {
 14         int next[26],ptr,num;// ptr在字典中的位置,num此结点出现几次,
 15         void init() {
 16             ptr=-1;
 17             num=0;
 18             mt(next,0);
 19         }
 20     } s[M];
 21     int ls,p;
 22     int f(char c) {
 23         return c-'a';
 24     }
 25 public:
 26     void init() {
 27         s[1].init();
 28         p=0;
 29         ls=2;
 30     }
 31     void Insert(char ch[]) {
 32         int head=1;
 33         for(int k=0; ch[k]; k++) {
 34             int id=f(ch[k]);
 35             if(!s[head].next[id]) {
 36                 s[head].next[id]=ls;
 37                 s[ls++].init();
 38             }
 39             head=s[head].next[id];
 40             s[head].num++;
 41         }
 42         s[head].ptr=p++;
 43     }
 44     int query(char ch[],int op) {
 45         int head=1;
 46         for(int k=0; ch[k]&&head; k++) {
 47             head=s[head].next[f(ch[k])];
 48         }
 49         if(op) { //op==1 查ptr
 50             if(head) return s[head].ptr;
 51             return -1;
 52         } else { //op==0 查num
 53             if(head) return s[head].num;
 54             return 0;
 55         }
 56     }
 57     void solve(int i,char ch[],LL dp[]){
 58         int head=1;
 59         for(int k=i;ch[k]&&head;k++){
 60             int id=f(ch[k]);
 61             if(!s[head].next[id]) return ;
 62             head=s[head].next[id];
 63             if(s[head].ptr!=-1){
 64                 dp[k+1]+=dp[i];
 65                 dp[k+1]%=MOD;
 66             }
 67         }
 68     }
 69 } trie;
 70 int n;
 71 char a[M];
 72 char b[4010][110];
 73 LL dp[M];
 74 void init_trie() {
 75     trie.init();
 76     for(int i=0; i<n; i++) {
 77         trie.Insert(b[i]);
 78     }
 79 }
 80 LL solve() {
 81     init_trie();
 82     int len=strlen(a);
 83     for(int i=0; i<=len; i++) {
 84         dp[i]=0;
 85     }
 86     dp[0]=1;
 87     for(int i=0; i<len; i++) {
 88         if(dp[i]==0) continue;
 89         trie.solve(i,a,dp);
 90     }
 91     return dp[len];
 92 }
 93 int main() {
 94 #ifdef txtout
 95     freopen("in.txt","r",stdin);
 96     freopen("out.txt","w",stdout);
 97 #endif // txtout
 98     int cas=1;
 99     while(~scanf("%s%d",a,&n)) {
100         for(int i=0; i<n; i++) {
101             scanf("%s",b[i]);
102         }
103         printf("Case %d: %lld\n",cas++,solve());
104     }
105     return 0;
106 }
View Code

 

 

例题12 uva 11732 http://acm.hust.edu.cn/vjudge/problem/28438

题意, 给n个字符串,用题目中的strcmp两两比较,需要执行多少次==判断.

暴力n2枚举, 最坏len计算次数.超时.

字典树做法,先把所有串插入字典树, 然后枚举一个串去字典树中查询, 对于串的每一位,都需要和所有串执行一次==,通过字典树节点记录的次数可以o1累加, 然后和该位置相等的串会多执行一次=='\0',也可以o1得到.

因为\0也会比较一次,而字典树中我没存,所以我在每个串后面加个#表示\0,这样比较时不需要特判他了.  然后每个串会多算一个和自己的次数,  扣去2倍的长度即可,因为和自己总是能比较到最后一位.  每一对会算两次,最后答案除2即可.

 

  1 //#define txtout
  2 //#define debug
  3 #include<bits/stdc++.h>
  4 #define mt(a,b) memset(a,b,sizeof(a))
  5 using namespace std;
  6 typedef long long LL;
  7 const double pi=acos(-1.0);
  8 const double eps=1e-8;
  9 const int inf=0x3f3f3f3f;
 10 const int M=4e3+10;
 11 class Trie_tree {   //字典树  前缀树
 12     struct node {
 13         int next[63],ptr,num;// ptr在字典中的位置,num此结点出现几次,
 14         void init() {
 15             ptr=-1;
 16             num=0;
 17             mt(next,0);
 18         }
 19     } s[M*1000];
 20     int ls,p;
 21     int f(char c) {
 22         if(c>='a'&&c<='z') return c-'a';
 23         if(c>='A'&&c<='Z') return c-'A'+26;
 24         if(c>='0'&&c<='9') return c-'0'+52;
 25         return 62;
 26     }
 27 public:
 28     void init() {
 29         s[1].init();
 30         p=0;
 31         ls=2;
 32     }
 33     void Insert(char ch[]) {
 34         int head=1;
 35         for(int k=0; ch[k]; k++) {
 36             int id=f(ch[k]);
 37             if(!s[head].next[id]) {
 38                 s[head].next[id]=ls;
 39                 s[ls++].init();
 40             }
 41             head=s[head].next[id];
 42             s[head].num++;
 43         }
 44         s[head].ptr=p++;
 45     }
 46     int query(char ch[],int op) {
 47         int head=1;
 48         for(int k=0; ch[k]&&head; k++) {
 49             head=s[head].next[f(ch[k])];
 50         }
 51         if(op) { //op==1 查ptr
 52             if(head) return s[head].ptr;
 53             return -1;
 54         } else { //op==0 查num
 55             if(head) return s[head].num;
 56             return 0;
 57         }
 58     }
 59     LL solve(char ch[]){
 60         LL sum=0;
 61         int head=1;
 62         LL presum=-1;
 63         for(int k=0; ch[k]&&head; k++) {
 64             if(presum==-1){
 65                 presum=0;
 66                 for(int i=0;i<63;i++){
 67                     int next=s[head].next[i];
 68                     if(!next) continue;
 69                     presum+=s[next].num;
 70                 }
 71             }
 72             sum+=presum;
 73             head=s[head].next[f(ch[k])];
 74             sum+=s[head].num;
 75             presum=s[head].num;
 76         }
 77         return sum;
 78     }
 79 } trie;
 80 int n;
 81 char a[M][M];
 82 LL solve(){
 83     trie.init();
 84     for(int i=0;i<n;i++){
 85         strcat(a[i],"#");
 86         trie.Insert(a[i]);
 87     }
 88     LL sum=0;
 89     for(int i=0;i<n;i++){
 90         sum+=trie.solve(a[i]);
 91         sum-=strlen(a[i])*2;
 92     }
 93     return sum/2;
 94 }
 95 int main(){
 96     #ifdef txtout
 97     freopen("in.txt","r",stdin);
 98     freopen("out.txt","w",stdout);
 99     #endif // txtout
100     int cas=1;
101     while(~scanf("%d",&n),n){
102         for(int i=0;i<n;i++){
103             scanf("%s",a[i]);
104         }
105         printf("Case %d: %lld\n",cas++,solve());
106     }
107     return 0;
108 }
View Code

 

 

 例题13 la 3026 http://acm.hust.edu.cn/vjudge/problem/29342

kmp例题, 又拿hash水过了, 发现hash虽然理论上有概率冲突,有概率出错, 但是实际使用起来, 很好.  

这题对每一个前缀,想知道该前缀最多能分成几块, 使得每一块都相等, 如果块数大于1,就输出.

hash解法, 枚举一个前缀, 然后枚举该前缀往后能有多少段相等, 每找到一个相等, 就能更新一次. 复杂度 n *( 1/1 + 1/2 + 1/n) 调和级数 并不大。 好像ln n吧? 

 

 1 //#define txtout
 2 //#define debug
 3 #include<bits/stdc++.h>
 4 #define mt(a,b) memset(a,b,sizeof(a))
 5 using namespace std;
 6 typedef long long LL;
 7 const double pi=acos(-1.0);
 8 const double eps=1e-8;
 9 const int inf=0x3f3f3f3f;
10 const int M=1e6+10;
11 class String_Hash {///字符串哈希 init O(n) query O(1)
12     typedef unsigned long long typec;///hash 值类型
13     static const int MV=1e6+10;///串长度
14     static const int key=137;///hash 种子值选素数好
15     typec H[MV],xp[MV];
16 public:
17     void init(char s[],int ls) { ///传入串数组和串长
18         H[ls]=0;
19         for(int i=ls-1; i>=0; i--) {
20             H[i]=H[i+1]*key+s[i];
21         }
22         xp[0]=1;
23         for(int i=1; i<=ls; i++) {
24             xp[i]=xp[i-1]*key;
25         }
26     } typec get(int pos,int len) { ///传入初始位置 pos,串长 len,返回串 hash 值
27         return H[pos]-H[pos+len]*xp[len];
28     }
29 } gx;
30 int n;
31 char a[M];
32 int b[M];
33 typedef pair<int,int> pii;
34 vector<pii> answer;
35 void init() {
36     int la=strlen(a);
37     for(int i=0; i<la; i++) {
38         b[i]=1;
39     }
40     gx.init(a,la);
41 }
42 void solve() {
43     init();
44     int la=strlen(a);
45     for(int i=0;i<la;i++){
46         int len=i+1;
47         for(int j=i+1;j+len-1<la;j+=len){
48             if(gx.get(0,len)!=gx.get(j,len)) break;
49             b[j+len-1]=max(b[j+len-1],(j+len)/len);
50         }
51     }
52     answer.clear();
53     for(int i=0;i<la;i++){
54         if(b[i]>1){
55             answer.push_back(make_pair(i+1,b[i]));
56         }
57     }
58 }
59 int main() {
60 #ifdef txtout
61     freopen("in.txt","r",stdin);
62     freopen("out.txt","w",stdout);
63 #endif // txtout
64     int cas=1;
65     while(~scanf("%d",&n),n) {
66         scanf("%s",a);
67         solve();
68         printf("Test case #%d\n",cas++);
69         for(int i=0; i<answer.size(); i++) {
70             printf("%d %d\n",answer[i].first,answer[i].second);
71         }
72         puts("");
73     }
74     return 0;
75 }
View Code

 

 白书kmp不是很容易理解 ,  先记录一下吧.

 1 //#define txtout
 2 //#define debug
 3 #include<bits/stdc++.h>
 4 #define mt(a,b) memset(a,b,sizeof(a))
 5 using namespace std;
 6 typedef long long LL;
 7 const double pi=acos(-1.0);
 8 const double eps=1e-8;
 9 const int inf=0x3f3f3f3f;
10 const int M=1e6+10;
11 int n;
12 char a[M];
13 int f[M];
14 typedef pair<int,int> pii;
15 vector<pii> answer;
16 void getFail(char* P,int* f){
17     int m=strlen(P);
18     f[0]=0;
19     f[1]=0;
20     for(int i=1;i<m;i++){
21         int j=f[i];
22         while(j&&P[i]!=P[j]) j=f[j];
23         f[i+1]=P[i]==P[j]?j+1:0;
24     }
25 }
26 void solve() {
27     getFail(a,f);
28     answer.clear();
29     int la=strlen(a);
30     for(int i=0;i<=la;i++){
31         if(f[i]>0&&i%(i-f[i])==0){
32             answer.push_back(make_pair(i,i/(i-f[i])));
33         }
34     }
35 }
36 int main() {
37 #ifdef txtout
38     freopen("in.txt","r",stdin);
39     freopen("out.txt","w",stdout);
40 #endif // txtout
41     int cas=1;
42     while(~scanf("%d",&n),n) {
43         scanf("%s",a);
44         solve();
45         printf("Test case #%d\n",cas++);
46         for(int i=0; i<answer.size(); i++) {
47             printf("%d %d\n",answer[i].first,answer[i].second);
48         }
49         puts("");
50     }
51     return 0;
52 }
View Code

 

 

例题14 la 4670 http://acm.hust.edu.cn/vjudge/problem/19224

ac自动机例题 不会, 但是kmp可以水过.  求出现次数最多的子串. 暴力一个个kmp看出现次数.

 1 //#define txtout
 2 //#define debug
 3 #include<bits/stdc++.h>
 4 #define mt(a,b) memset(a,b,sizeof(a))
 5 using namespace std;
 6 typedef long long LL;
 7 const double pi=acos(-1.0);
 8 const double eps=1e-8;
 9 const int inf=0x3f3f3f3f;
10 const int M=1e6+10;
11 class KMP { ///模式匹配(kmp)O(ls+lp)
12     typedef char typec;///文本元素的类型
13     static const int MV=1e6+10;///字符串的长度
14     int next[MV];
15 public:///匹配串长度 ls,str 存待匹配文本,模式串长度 lp,pat 存模式串
16     int kmp(int ls,typec str[],int lp,typec pat[],int res[]) { ///返回匹配次数,res 中存储每个匹配的初始位置
17         int i=0,j=-1,cnt=0;
18         next[0]=-1;
19         while(i<lp) {
20             if(j==-1||pat[i]==pat[j]) {
21                 next[++i]=++j;
22                 continue;
23             }
24             j=next[j];
25         }
26         i=j=0;
27         while(i<ls) {
28             while(j!=lp&&str[i]==pat[j]) {
29                 i++;
30                 j++;
31             }
32             if(!j) {
33                 i++;
34                 continue;
35             }
36             if(j==lp) {
37                 res[cnt++]=i-j;
38             }
39             j=next[j];
40         }
41         return cnt;
42     }
43 } gx;
44 int n;
45 struct Q{
46     char a[128];
47     int time;
48 }q[210];
49 char b[M];
50 int res[M];
51 int answer;
52 void solve(){
53     answer=0;
54     int lb=strlen(b);
55     for(int i=0;i<n;i++){
56         q[i].time=gx.kmp(lb,b,strlen(q[i].a),q[i].a,res);
57         answer=max(answer,q[i].time);
58     }
59 }
60 int main() {
61 #ifdef txtout
62     freopen("in.txt","r",stdin);
63     freopen("out.txt","w",stdout);
64 #endif // txtout
65     while(~scanf("%d",&n),n) {
66         for(int i=0; i<n; i++) {
67             scanf("%s",q[i].a);
68         }
69         scanf("%s",b);
70         solve();
71         printf("%d\n",answer);
72         for(int i=0;i<n;i++){
73             if(q[i].time==answer){
74                 puts(q[i].a);
75             }
76         }
77     }
78     return 0;
79 }
View Code

ac自动机代码 need to write.

 

 

 例题15 uva 11468 

ac自动机  need to write.

 

例题16  uva 11019

 

暴力kmp加bitset 水过.  求一个字符矩阵在一个大字符矩阵出现几次.  枚举每一行, bitset每一位 1 表示该位为起点匹配上了, x行与运算, 1的个数就是矩阵匹配次数, 中间也可以break 剪枝.

  1 //#define txtout
  2 //#define debug
  3 #include<bits/stdc++.h>
  4 #define mt(a,b) memset(a,b,sizeof(a))
  5 using namespace std;
  6 typedef long long LL;
  7 const double pi=acos(-1.0);
  8 const double eps=1e-8;
  9 const int inf=0x3f3f3f3f;
 10 const int M=1e3+10;
 11 class KMP { ///模式匹配(kmp)O(ls+lp)
 12     typedef char typec;///文本元素的类型
 13     static const int MV=1e3+10;///字符串的长度
 14     int next[MV];
 15 public:///匹配串长度 ls,str 存待匹配文本,模式串长度 lp,pat 存模式串
 16     int kmp(int ls,typec str[],int lp,typec pat[],int res[]) { ///返回匹配次数,res 中存储每个匹配的初始位置
 17         int i=0,j=-1,cnt=0;
 18         next[0]=-1;
 19         while(i<lp) {
 20             if(j==-1||pat[i]==pat[j]) {
 21                 next[++i]=++j;
 22                 continue;
 23             }
 24             j=next[j];
 25         }
 26         i=j=0;
 27         while(i<ls) {
 28             while(j!=lp&&str[i]==pat[j]) {
 29                 i++;
 30                 j++;
 31             }
 32             if(!j) {
 33                 i++;
 34                 continue;
 35             }
 36             if(j==lp) {
 37                 res[cnt++]=i-j;
 38             }
 39             j=next[j];
 40         }
 41         return cnt;
 42     }
 43 } gx;
 44 int n,m,x,y;
 45 char a[M][M];
 46 char b[M][M];
 47 int la[M];
 48 int lb[M];
 49 bitset<1000> b1,b2;
 50 int res[M];
 51 int solve(){
 52     for(int i=0;i<n;i++){
 53         la[i]=strlen(a[i]);
 54     }
 55     for(int i=0;i<x;i++){
 56         lb[i]=strlen(b[i]);
 57     }
 58     int sum=0;
 59     for(int i=0;i+x-1<n;i++){
 60         b1.reset();
 61         for(int j=0;j<m;j++){
 62             b1.set(j);
 63         }
 64         for(int j=0;j<x;j++){
 65             int time=gx.kmp(la[i+j],a[i+j],lb[j],b[j],res);
 66             if(time==0){
 67                 b1.reset();
 68                 break;
 69             }
 70             b2.reset();
 71             for(int k=0;k<time;k++){
 72                 b2.set(res[k]);
 73             }
 74             b1&=b2;
 75             if(b1.count()==0) break;
 76         }
 77         sum+=b1.count();
 78     }
 79     return sum;
 80 }
 81 int main() {
 82 #ifdef txtout
 83     freopen("in.txt","r",stdin);
 84     freopen("out.txt","w",stdout);
 85 #endif // txtout
 86     int t;
 87     while(~scanf("%d",&t)) {
 88         while(t--){
 89             scanf("%d%d",&n,&m);
 90             for(int i=0;i<n;i++){
 91                 scanf("%s",a[i]);
 92             }
 93             scanf("%d%d",&x,&y);
 94             for(int i=0;i<x;i++){
 95                 scanf("%s",b[i]);
 96             }
 97             printf("%d\n",solve());
 98         }
 99     }
100     return 0;
101 }
View Code

 

 不用bitset会慢一些, 常数

  1 //#define txtout
  2 //#define debug
  3 #include<bits/stdc++.h>
  4 #define mt(a,b) memset(a,b,sizeof(a))
  5 using namespace std;
  6 typedef long long LL;
  7 const double pi=acos(-1.0);
  8 const double eps=1e-8;
  9 const int inf=0x3f3f3f3f;
 10 const int M=1e3+10;
 11 class KMP { ///模式匹配(kmp)O(ls+lp)
 12     typedef char typec;///文本元素的类型
 13     static const int MV=1e3+10;///字符串的长度
 14     int next[MV];
 15 public:///匹配串长度 ls,str 存待匹配文本,模式串长度 lp,pat 存模式串
 16     int kmp(int ls,typec str[],int lp,typec pat[],int res[]) { ///返回匹配次数,res 中存储每个匹配的初始位置
 17         int i=0,j=-1,cnt=0;
 18         next[0]=-1;
 19         while(i<lp) {
 20             if(j==-1||pat[i]==pat[j]) {
 21                 next[++i]=++j;
 22                 continue;
 23             }
 24             j=next[j];
 25         }
 26         i=j=0;
 27         while(i<ls) {
 28             while(j!=lp&&str[i]==pat[j]) {
 29                 i++;
 30                 j++;
 31             }
 32             if(!j) {
 33                 i++;
 34                 continue;
 35             }
 36             if(j==lp) {
 37                 res[cnt++]=i-j;
 38             }
 39             j=next[j];
 40         }
 41         return cnt;
 42     }
 43 } gx;
 44 int n,m,x,y;
 45 char a[M][M];
 46 char b[M][M];
 47 int la[M];
 48 int lb[M];
 49 bool b1[M];
 50 bool b2[M];
 51 int res[M];
 52 int solve(){
 53     for(int i=0;i<n;i++){
 54         la[i]=strlen(a[i]);
 55     }
 56     for(int i=0;i<x;i++){
 57         lb[i]=strlen(b[i]);
 58     }
 59     int sum=0;
 60     for(int i=0;i+x-1<n;i++){
 61         int one=m;
 62         for(int j=0;j<m;j++){
 63             b1[j]=true;
 64         }
 65         for(int j=0;j<x;j++){
 66             int time=gx.kmp(la[i+j],a[i+j],lb[j],b[j],res);
 67             if(time==0){
 68                 one=0;
 69                 break;
 70             }
 71             for(int k=0;k<m;k++){
 72                 b2[k]=false;
 73             }
 74             for(int k=0;k<time;k++){
 75                 b2[res[k]]=true;
 76             }
 77             for(int k=0;k<m;k++){
 78                 if(b1[k]&&b2[k]) continue;
 79                 if(b1[k]&&!b2[k]){
 80                     b1[k]=false;
 81                     one--;
 82                     if(one==0) break;
 83                 }
 84             }
 85             if(one==0) break;
 86         }
 87         sum+=one;
 88     }
 89     return sum;
 90 }
 91 int main() {
 92 #ifdef txtout
 93     freopen("in.txt","r",stdin);
 94     freopen("out.txt","w",stdout);
 95 #endif // txtout
 96     int t;
 97     while(~scanf("%d",&t)) {
 98         while(t--){
 99             scanf("%d%d",&n,&m);
100             for(int i=0;i<n;i++){
101                 scanf("%s",a[i]);
102             }
103             scanf("%d%d",&x,&y);
104             for(int i=0;i<x;i++){
105                 scanf("%s",b[i]);
106             }
107             printf("%d\n",solve());
108         }
109     }
110     return 0;
111 }
View Code

 

ac自动机 need to write.

 

 

 

 

end

posted on 2016-08-13 17:09  gaolzzxin  阅读(146)  评论(0编辑  收藏  举报