2754: [SCOI2012]喵星球上的点名
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 649 Solved: 305
[Submit][Status]
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。
Source
很裸很裸的AC自动机。只不过这道题让我基本搞懂了stl map的用法。
map.insert(pair) 插入映射关系
map.find(x) 查询x映射的关系,返回一个迭代器,可用first,second查找
map<int,int>::iterator it1; 迭代器
另外AC自动机的一个小细节,让我Wa了两遍:
fail指针如果需要指向深度为1的节点时要特判,而且对于已经确定fail指针的节点,切忌重新复制(其实就是if语句条件要严密)。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<vector> using namespace std; #define MAXT 201000 #define MAXN MAXT vector<int> query[MAXN]; int query_gets[MAXN]; int cat_gets[MAXN]; int qur_vis[MAXN]; int topq=-1; struct aaa { int id; int fail; int qur_id; map<int,int> next; aaa() { qur_id=id=fail=-1; } }; int root; aaa tree[MAXT]; int topt=0; int name[MAXN],topn=-1; int str[MAXN]; int n,m; void add_str(int * str,int qur) { int ind; int now=root; map<int,int>::iterator it1; while (*str!=-1) { ind=*(str++); it1=tree[now].next.find(ind); if (it1==tree[now].next.end()) { tree[now].next.insert(make_pair(ind,++topt)); tree[topt].id=ind; now=topt; }else { now=it1->second; } } if (tree[now].qur_id==-1) { tree[now].qur_id=++topq; query[topq].push_back(qur); }else { query[tree[now].qur_id].push_back(qur); } } int q[MAXT]; void build_tree() { int ope=0,clo=0,now,temp,x,ind; map<int,int>::iterator it1,it2; tree[0].fail=0; for (it1=tree[0].next.begin();it1!=tree[0].next.end();it1++) { now=it1->second; q[++clo]=now; tree[now].fail=0; } while (ope<clo) { now=q[++ope]; for (it1=tree[now].next.begin();it1!=tree[now].next.end();it1++) { x=it1->second; ind=it1->first; q[++clo]=x; temp=tree[now].fail; while (temp!=root) { it2=tree[temp].next.find(ind); if (it2!=tree[temp].next.end()) { tree[x].fail=it2->second; break; } temp=tree[temp].fail; } it2=tree[root].next.find(ind); if (tree[x].fail==-1&&it2!=tree[root].next.end())//Oh, I forgot this part again { tree[x].fail=it2->second; } if (tree[x].fail==-1) { tree[x].fail=0; } } } } int count_str(int *str,int cat_id) { int ret=0; int now=0; int ind,x,temp; int i; map<int,int>::iterator it1; while (*str!=-1) { ind=*(str++); it1=tree[now].next.find(ind); while (now!=root&&it1==tree[now].next.end()) { now=tree[now].fail; it1=tree[now].next.find(ind); } if (it1==tree[now].next.end()) { now=root; }else { now=it1->second; } temp=now; while (temp!=root) { if (tree[temp].qur_id!=-1) { x=tree[temp].qur_id; for (i=0;i<query[x].size();i++) { if(qur_vis[query[x][i]]!=cat_id) { query_gets[query[x][i]]++; ret++; qur_vis[query[x][i]]=cat_id; } } } temp=tree[temp].fail; } } return ret; } void init() { topt=0; tree[0].id=-1; root=0; int i,j,x,y; scanf("%d%d",&n,&m); for (i=0;i<n*2;i++) { scanf("%d",&x); name[++topn]=x; for (j=0;j<x;j++) { scanf("%d",&y); name[++topn]=y; } name[++topn]=-1; } for (i=0;i<m;i++) { scanf("%d",&x); for (j=0;j<x;j++) { scanf("%d",&y); str[j]=y; } str[x]=-1; add_str(str,i); } build_tree(); memset(qur_vis,-1,sizeof(qur_vis)); } void work() { int i; int now=0; for (i=0;i<n*2;i++) { now++; cat_gets[i/2]+=count_str(&name[now],i/2); now+=name[now-1]; now++; } for (i=0;i<m;i++) { printf("%d ",query_gets[i]); } for (i=0;i<n-1;i++) { printf("%d ",cat_gets[i]); } printf("%d ",cat_gets[n-1]); } int main() { init(); work(); return 0; }