SCOI 2012 Day 1 喵星球上的点名
题目摘自:http://61.187.179.132/JudgeOnline/problem.php?id=2754
题目描述:
Time Limit: 20 Sec Memory Limit: 128 MB
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
1
0
1 2
【提示】
事实上样例给出的数据如果翻译成地球上的语言可以这样来看
2 3
izayoi sakuya
orihara izaya
izay
hara
raiz
【数据范围】
对于30%的数据,保证:
1<=N,M<=1000,喵星人的名字总长不超过4000,点名串的总长不超过2000。
对于100%的数据,保证:
1<=N<=20000,1<=M<=50000,喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过10000。
这是四川省今年的省选题。话说当时我去做的时候什么都不知道,连KMP都没写过就直接面对这个伟大的匹配问题,自然只有裸了,结果得了我考试中唯一的30分。下来后自己看了看KMP,又写了一下,对字符串匹配有了基本的了解,然后准备挑战这道题。据说是可以用后缀数组做的,但是MS我同学在OJ上没有过,于是果断套上AC自动机。本题其实就是把m个串建成自动机,然后拿n个串依次询问即可。
参考了zhx大神的代码,自己又拿回去写了一遍,终于通过了。算是来个纪念吧。
![](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 #define maxm 50001 10 #define maxn 20001 11 #define maxl 100001 12 13 int n,m,l,q[maxm],nowname[maxl],next[maxm],all,check[maxm],v[maxl],answer[maxn],ask[maxm]; 14 15 struct na 16 { 17 int p1,l1,p2,l2; 18 }name[maxn]; 19 20 struct node 21 { 22 int count; 23 map<int,node*> next; 24 node *fail; 25 26 node() 27 { 28 count=0; 29 fail=NULL; 30 } 31 }; 32 33 queue<node*> que; 34 35 void insert(node *root,int *nowstr,int now) 36 { 37 int l=0; 38 node* p=root; 39 40 while(nowstr[l]!=-1) 41 { 42 if(p->next[nowstr[l]]==NULL) p->next[nowstr[l]]=new node; 43 p=p->next[nowstr[l]]; 44 l++; 45 } 46 47 all++; 48 q[all]=now; 49 next[all]=p->count; 50 p->count=all; 51 } 52 53 void build_AC(node* root) 54 { 55 que.push(root); 56 root->fail=NULL; 57 58 while(!que.empty()) 59 { 60 node* p=que.front(); 61 que.pop(); 62 63 for(map<int,node*>::iterator i=p->next.begin();i!=p->next.end();i++) 64 if(i->second!=NULL) 65 { 66 node *x=i->second; 67 int v=i->first; 68 69 node *last=p->fail; 70 while(last!=NULL) 71 { 72 if(last->next[v]!=NULL) 73 { 74 x->fail=last->next[v]; 75 break; 76 } 77 last=last->fail; 78 } 79 80 if(last==NULL) x->fail=root; 81 int nowp=x->count,lastp=0; 82 while(nowp!=0) 83 { 84 lastp=nowp; 85 nowp=next[nowp]; 86 } 87 if(lastp==0) x->count=x->fail->count; 88 else next[lastp]=x->fail->count; 89 que.push(x); 90 } 91 } 92 } 93 94 void query(node *root,int now) 95 { 96 int l=name[now].p1; 97 node *p=root; 98 99 while(l<=name[now].p1+name[now].l1-1) 100 { 101 while(p->next[v[l]]==NULL&&p!=root) 102 p=p->fail; 103 104 p=p->next[v[l]]; 105 if(p==NULL) p=root; 106 else 107 { 108 int nowp=p->count; 109 while(nowp!=0) 110 { 111 if(check[q[nowp]]!=now) 112 { 113 check[q[nowp]]=now; 114 answer[now]++; 115 ask[q[nowp]]++; 116 } 117 nowp=next[nowp]; 118 } 119 } 120 l++; 121 } 122 123 l=name[now].p2; 124 p=root; 125 126 while(l<=name[now].p2+name[now].l2-1) 127 { 128 while(p->next[v[l]]==NULL&&p!=root) 129 p=p->fail; 130 131 p=p->next[v[l]]; 132 if(p==NULL) p=root; 133 else 134 { 135 int nowp=p->count; 136 while(nowp!=0) 137 { 138 if(check[q[nowp]]!=now) 139 { 140 check[q[nowp]]=now; 141 answer[now]++; 142 ask[q[nowp]]++; 143 } 144 nowp=next[nowp]; 145 } 146 } 147 l++; 148 } 149 } 150 151 int main() 152 { 153 scanf("%d%d",&n,&m); 154 l=-1; 155 156 for(int i=1;i<=n;i++) 157 { 158 scanf("%d",&name[i].l1); 159 name[i].p1=l+1; 160 for(int j=1;j<=name[i].l1;j++) 161 { 162 l++; 163 scanf("%d",&v[l]); 164 } 165 166 scanf("%d",&name[i].l2); 167 name[i].p2=l+1; 168 for(int j=1;j<=name[i].l2;j++) 169 { 170 l++; 171 scanf("%d",&v[l]); 172 } 173 } 174 175 node *root=new node; 176 for(int i=1;i<=m;i++) 177 { 178 int nowl; 179 scanf("%d",&nowl); 180 for(int j=0;j<nowl;j++) 181 scanf("%d",&nowname[j]); 182 nowname[nowl]=-1; 183 insert(root,nowname,i); 184 } 185 186 build_AC(root); 187 188 for(int i=1;i<=n;i++) query(root,i); 189 for(int i=1;i<=m;i++) printf("%d\n",ask[i]); 190 for(int i=1;i<=n;i++) 191 { 192 printf("%d",answer[i]); 193 if(i==n) printf("\n"); 194 else printf(" "); 195 } 196 197 return 0; 198 }