bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)相关的知识,希望对你有一定的参考价值。
2754: [SCOI2012]喵星球上的点名
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 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
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]喵星球上的点名(后缀数组)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)
bzoj2754 [SCOI2012]喵星球上的点名 (后缀数组+树状数组)