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

Sample Output

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大神的代码,自己又拿回去写了一遍,终于通过了。算是来个纪念吧。

 

View Code
  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 }

 

 

 

posted on 2012-05-27 15:54  stickjitb  阅读(330)  评论(1编辑  收藏  举报