码迷,mamicode.com
首页 > 编程语言 > 详细

bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)

时间:2016-02-20 13:21:27      阅读:464      评论:0      收藏:0      [点我收藏+]

标签:

 

2754: [SCOI2012]喵星球上的点名

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 1359  Solved: 618
[Submit][Status][Discuss]

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

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。

 

【思路】

 

       后缀数组

       将所有的串连起来,包括姓名和询问。处理出rank[],sa[],height[],通过rank确定一个询问的位置,然后在height上左右各扫一下,统计即可。flag对同一只标记,kase是时间戳(也算知道叫什么了=-=)

 

【代码】

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 const int N = 3*1e5+1e2;
  8 
  9 int s[N];
 10 int sa[N],height[N],rank[N],t[N],t2[N],c[N];
 11 
 12 void build_sa(int m,int n) {
 13     int i,k,*x=t,*y=t2;
 14     for(i=0;i<m;i++) c[i]=0;
 15     for(i=0;i<n;i++) c[x[i]=s[i]]++;
 16     for(i=0;i<m;i++) c[i]+=c[i-1];
 17     for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
 18     for(k=1;k<=n;k<<=1) {
 19         int p=0;
 20         for(i=n-k;i<n;i++) y[p++]=i;
 21         for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
 22         for(i=0;i<m;i++) c[i]=0;
 23         for(i=0;i<n;i++) c[x[y[i]]]++;
 24         for(i=0;i<m;i++) c[i]+=c[i-1];
 25         for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
 26         swap(x,y);
 27         p=1; x[sa[0]]=0;
 28         for(i=1;i<n;i++) 
 29             x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]? p-1:p++;
 30         if(p>=n) break;
 31         m=p;
 32     }
 33 }
 34 void get_height(int n) {
 35     int i,j,k=0;
 36     for(i=0;i<n;i++) rank[sa[i]]=i;
 37     for(i=0;i<n;i++) {
 38         if(k) k--;
 39         j=sa[rank[i]-1];
 40         while(s[i+k]==s[j+k]) k++;
 41         height[rank[i]]=k;
 42     }
 43 }
 44 
 45 int n,m;
 46 int flag[N],kase,ans[N],from[N],que[N],length[N];
 47 void read(int& x) {
 48     char c=getchar(); int f=1; x=0;
 49     while(!isdigit(c)){if(c==-)f=-1; c=getchar();}
 50     while(isdigit(c)) x=x*10+c-0,c=getchar();
 51     x*=f;
 52 }
 53 int main() {
 54     memset(from,-1,sizeof(from));
 55     read(n),read(m);
 56     int x,len=0;
 57     for(int i=0;i<n;i++) {
 58         read(x);
 59         for(int j=0;j<x;j++)
 60             read(s[len]),from[len++]=i;
 61         s[len++]=10001;
 62         read(x);
 63         for(int j=0;j<x;j++)
 64             read(s[len]),from[len++]=i;
 65         s[len++]=10001;
 66     }
 67     for(int i=0;i<m;i++) {
 68         read(x);
 69         que[i]=len; length[i]=x;
 70         for(int j=0;j<x;j++)
 71             read(s[len++]);
 72         s[len++]=10001;
 73     }
 74     build_sa(10002,len);
 75     get_height(len);
 76     for(int i=0;i<m;i++) {
 77         int p=rank[que[i]],tot=0;
 78         ++kase;
 79         while(height[p]>=length[i]) {
 80             if(from[sa[p-1]]!=-1)
 81                 if(flag[from[sa[p-1]]]!=kase) {
 82                     flag[from[sa[p-1]]]=kase;
 83                     ++tot;
 84                     ++ans[from[sa[p-1]]];
 85                 }
 86             p--;
 87             if(!p) break;
 88         }
 89         p=rank[que[i]];
 90         while(height[p+1]>=length[i]) {
 91             if(from[sa[p+1]]!=-1)
 92                 if(flag[from[sa[p+1]]]!=kase) {
 93                     flag[from[sa[p+1]]]=kase;
 94                     ++tot;
 95                     ++ans[from[sa[p+1]]];
 96                 }
 97             p++;
 98             if(p==len) break;
 99         }
100         printf("%d\n",tot);
101     }
102     printf("%d",ans[0]);
103     for(int i=1;i<n;i++) printf(" %d",ans[i]);
104 }

 

bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)

标签:

原文地址:http://www.cnblogs.com/lidaxin/p/5203079.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!