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

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 }
时间: 2024-07-30 10:10:10

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

BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

BZOJ 2754([SCOI2012]喵星球上的点名-后缀数组统计序列集合中子序列出现次数)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 805  Solved: 380 [Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,

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

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1926  Solved: 850[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这

BZOJ 2754 SCOI2012 喵星球上的点名 fail树+set启发式合并

题目大意:给定n个目标串和m个模式串,问这m个模式串每个在多少个目标串中出现过,以及n个目标串每个以最多多少个模式串为子串 我错了--就算用fail树+set启发式合并也优化不到O(nlog^2n)--这题的数据范围相当无解啊 首先将所有名字和点名的字符串全都插进AC自动机 将每个点上开一个set记录这个点是哪些喵星人的名字的前缀 然后建立fail树 沿着fail树从下到上启发式合并 每合并完一个点 如果这个点是某次点名的字符串 那么这次点名点到的喵星人就是这个点的set中的所有元素 统计答案即

bzoj 2754 [SCOI2012]喵星球上的点名 (AC自动机+map维护Trie树)

题目大意:略 由于字符集大,要用map维护Trie树 并不能用AC自动机的Trie图优化,不然内存会炸 所以我用AC自动机暴跳fail水过的 显然根据喵星人建AC自动机是不行的,所以要根据问题建 然而这题有一些很艮的地方: 1.如果一个喵的名和姓都被点到,那他只被点到了一次 2.询问的串可能相同 3.如果map中并不包含某个元素,但你强行用数组表示它,那么它会返回0,然后这个元素会被强行插入map并赋值成0 1 #include <map> 2 #include <queue> 3

BZOJ 2754 SCOI 2012 喵星球上的点名 后缀数组

题目大意:在喵星球上有一些喵~,每个喵都有一个姓和一个名字.点名的时候如果一个喵中姓或者名中有这个串的话他就会喵.问每次点名有几个喵喵了,和每个喵喵了几次. 思路:好萌的题喵~ AC自动机构造fail树是可以做的,但是和SA乱搞的时间差不多,我就是SA乱搞的w 把所有的串(姓名,询问)用$连接成一个串,然后做后缀数组,height数组.过程中记录一下每一个后缀数属于哪个喵,还有询问在串中的起始位置.在处理询问的时候,可以同过sa,rank数组快速的访问height数组,对于每一个询问向两边拓展,

【BZOJ2754】【SCOI2012】喵星球上的点名 后缀数组优化暴力

转载请注明出处谢谢:http://blog.csdn.net/vmurder/article/details/42963375 题意: 那个输入中每个串先是一个长度然后才是串. 然后如果某猫姓名abcd·efgh,那么点名abc,bcd,fg等都是好使的,但是cde就不行. 然后输入姓名时格式为一行 a a个数,b b个数. A表示姓,B表示名. 题解: 直接暴力枚举每个点名是哪些的子串, 然后我们发现可以用后缀数组来优化这个事情~~ 时间复杂度是不准确的,也就是说可以被卡成TLE,但是大家都没

bzoj2754 [SCOI2012]喵星球上的点名 (后缀数组+树状数组)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 2745 Solved: 1190 [Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么

P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队)

P2336 [SCOI2012]喵星球上的点名 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> #define rint register int using namespace std; int read(){ char c=getchar();int x=0; while(