SCOI 2012 喵星球上的点名
题目:http://61.187.179.132/JudgeOnline/problem.php?id=2754
Description
a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?
Input
现在定义喵星球上的字符串给定方法:
先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数N和M。
接下来有N行,每行包含第i 个喵星人的姓和名两个串。姓和名都是标准的喵星球上的
字符串。
接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。
Output
对于每个老师点名的串输出有多少个喵星人应该答到。
然后在最后一行输出每个喵星人被点到多少次。
Sample Input
2 3
6 8 25 0 24 14 8 6 18 0 10 20 24 0
7 14 17 8 7 0 17 0 5 8 25 0 24 0
4 8 25 0 24
4 7 0 17 0
4 17 0 8 25
6 8 25 0 24 14 8 6 18 0 10 20 24 0
7 14 17 8 7 0 17 0 5 8 25 0 24 0
4 8 25 0 24
4 7 0 17 0
4 17 0 8 25
Sample Output
2
1
0
1 2
【提示】
事实上样例给出的数据如果翻译成地球上的语言可以这样来看
2 3
izayoi sakuya
orihara izaya
izay
hara
raiz
HINT
【数据范围】
对于30%的数据,保证:
1<=N,M<=1000,喵星人的名字总长不超过4000,点名串的总长不超过2000。
对于100%的数据,保证:
1<=N<=20000,1<=M<=50000,喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过10000。
题解:
题意简化后就是询问m个串在另外n个串中个出现了多少次。
于是就是经典的字符串匹配模型了。
用后缀数组MS可以搞,但是我不会。
于是就用AC自动机了,把m个串建成自动机,然后一个一个地把n个串带进去询问就行了,跟裸的自动机没多大区别。
考试的时候打掉了一行话,果断就悲剧掉了…………………………
题其实不难,能否1A才是关键。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<map>
5 #include<queue>
6
7 using namespace std;
8
9 const int maxl=100001;
10 const int maxn=20001;
11 const int maxm=50001;
12
13 int q[maxm],nownum[maxl],next[maxm],ll,check[maxm],v[maxl],answer[maxn],ask[maxm],n,m,l;
14
15 struct person
16 {
17 int p1,l1,l2,p2;
18 }pe[maxn];
19
20 struct node
21 {
22 int ans_f;
23 map < int , node * > next;
24 node *fail;
25 node()
26 {
27 fail=0;
28 ans_f=0;
29 }
30 };
31
32 queue<node *> que;
33
34 void insert(node *root,int *nownum,int now)
35 {
36 int l=0;
37 node *p=root;
38 while (nownum[l]!=-1)
39 {
40 if (p->next[nownum[l]]==NULL) p->next[nownum[l]]=new node;
41 p=p->next[nownum[l]];
42 l++;
43 }
44 ll++;
45 q[ll]=now;
46 next[ll]=p->ans_f;
47 p->ans_f=ll;
48 }
49
50 void build_AC(node *root)
51 {
52 que.push(root);
53 root->fail=NULL;
54 while (que.size())
55 {
56 node *p=que.front();
57 que.pop();
58 for (map < int , node * >::iterator crf=p->next.begin();crf!=p->next.end();crf++)
59 if (crf->second!=NULL)
60 {
61 node *ljl=crf -> second;
62 int v= crf -> first;
63 node *last=p->fail;
64 while (last!=NULL)
65 {
66 if (last->next[v]!=NULL)
67 {
68 ljl->fail=last->next[v];
69 break;
70 }
71 last=last->fail;
72 }
73 if (last==NULL) ljl->fail=root;
74 int nowp=ljl->ans_f,lastp=0;
75 while (nowp!=0)
76 {
77 lastp=nowp;
78 nowp=next[nowp];
79 }
80 if (lastp==0) ljl->ans_f=ljl->fail->ans_f;
81 else next[lastp]=ljl->fail->ans_f;
82 que.push(ljl);
83 }
84 }
85 }
86
87 void query(node *root,int now)
88 {
89 int l=pe[now].p1;
90 node *p=root;
91 while (l<=pe[now].p1+pe[now].l1-1)
92 {
93 while (p!=root && p->next[v[l]]==NULL)
94 p=p->fail;
95 p=p->next[v[l]];
96 if (p==NULL) p=root;
97 else
98 {
99 int nowp=p->ans_f;
100 while (nowp!=0)
101 {
102 if (check[q[nowp]]!=now)
103 {
104 check[q[nowp]]=now;
105 answer[now]++;
106 ask[q[nowp]]++;
107 }
108 nowp=next[nowp];
109 }
110 }
111 l++;
112 }
113 l=pe[now].p2;
114 p=root;
115 while (l<=pe[now].p2+pe[now].l2-1)
116 {
117 while (p!=root && p->next[v[l]]==NULL)
118 p=p->fail;
119 p=p->next[v[l]];
120 if (p==NULL) p=root;
121 else
122 {
123 int nowp=p->ans_f;
124 while (nowp!=0)
125 {
126 if (check[q[nowp]]!=now)
127 {
128 check[q[nowp]]=now;
129 answer[now]++;
130 ask[q[nowp]]++;
131 }
132 nowp=next[nowp];
133 }
134 }
135 l++;
136 }
137 }
138
139 int main()
140 {
141 //freopen("name.in","r",stdin);
142 //freopen("name.out","w",stdout);
143
144 scanf("%d%d",&n,&m);
145 l=-1;
146 for (int a=1;a<=n;a++)
147 {
148 scanf("%d",&pe[a].l1);
149 pe[a].p1=l+1;
150 for (int b=1;b<=pe[a].l1;b++)
151 {
152 l++;
153 scanf("%d",&v[l]);
154 }
155 scanf("%d",&pe[a].l2);
156 pe[a].p2=l+1;
157 for (int b=1;b<=pe[a].l2;b++)
158 {
159 l++;
160 scanf("%d",&v[l]);
161 }
162 }
163 node *root=new node;
164 for (int a=1;a<=m;a++)
165 {
166 int nowl;
167 scanf("%d",&nowl);
168 for (int b=0;b<nowl;b++)
169 scanf("%d",&nownum[b]);
170 nownum[nowl]=-1;
171 insert(root,nownum,a);
172 }
173 build_AC(root);
174 for (int a=1;a<=n;a++)
175 query(root,a);
176 for (int a=1;a<=m;a++)
177 printf("%d\n",ask[a]);
178 for (int a=1;a<=n;a++)
179 {
180 printf("%d",answer[a]);
181 if (a==n) printf("\n");
182 else printf(" ");
183 }
184
185 return 0;
186 }