【2012四川省选】喵星球上的点名
时间限制: 2000 ms 内存限制: 131072 KB
【题目描述】
a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非
常有趣。
假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。
然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?
【输入】
现在定义喵星球上的字符串给定方法:
先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数N和M。
接下来有N行,每行包含第i个喵星人的姓和名两个串。姓和名都是标准的喵星球上的字符串。
接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。
【输出】
对于每个老师点名的串输出有多少个喵星人应该答到。
然后在最后一行输出每个喵星人被点到多少次。
【输入样例】
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 2
5
【输出样例】
2
1
0
1 2
【提示】
【提示】
事实上样例给出的数据如果翻译成地球上的语言可以这样来看
2 3
izayoi sakuya
orihara izaya
izay
hara
raiz
【数据范围】
对于30%的数据,保证:
1<=N,M<=1000,喵星人的名字总长不超过4000,点名串的总长不超过2000,
对于100%的数据,保证:
1<=N<=2000,1<=M<=5000,喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过10000。
思路:这道题我们是先将每个“字符串”连接起来,然后用后缀数组求出sa和height数组,这样我们还要记录一个每个询问串的首字母在r数组里的位置
那么我们很容易就知道,从这个首字母的位置的height值开始向上和向下for一遍,如果当h[i]<该查询字符串的长度,也就是说没有公共前缀,这样可以直接break掉,另外一个就是去重
但这个算法很容易就被卡掉,例如全部输入数据都是0('a'),然后查询的串也是a,这样复杂度就是o(m*r的长度),肯定要T的,但是BZOJ上数据不严,但在UESTC_OJ上就T掉了- -,
正解呢我知道是离线+RMQ+树状数组,我暂时还不会,改天再更新吧,我暂时贴上我的代码。
1 /************************************************************** 2 Problem: 2754 3 User: cssystem 4 Language: C++ 5 Result: Accepted 6 Time:5748 ms 7 Memory:17688 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <iostream> 13 #include <cmath> 14 #include <algorithm> 15 #include <set> 16 using namespace std; 17 18 const int maxn=350100,maxm=10100; 19 int wa[maxn],wb[maxn],wv[maxn],wss[maxn],sa[maxn],q[maxn]; 20 int rank[maxn],h[maxn],num[maxn],r[maxn],rec[maxn],name[maxn]; 21 int t1,t2,n,m,x,y,cnt,maxlegal; 22 23 set<int> s; 24 set<int>::iterator it; 25 26 void close() 27 { 28 exit(0); 29 } 30 31 void work() 32 { 33 memset(name,0,sizeof(name)); 34 int t; 35 for (int i=1;i<=t2;i++) 36 { 37 s.clear(); 38 t=rank[rec[i]]; 39 for (int j=t;j>=1;j--) 40 { 41 if (h[j]<q[i]) break; 42 if (sa[j-1]>=maxlegal) continue; 43 s.insert(num[sa[j-1]]); 44 } 45 for (int j=t+1;j<=n;j++) 46 { 47 if (h[j]<q[i]) break; 48 if (sa[j]>=maxlegal) continue; 49 s.insert(num[sa[j]]); 50 } 51 for (it=s.begin();it!=s.end();it++) 52 name[*it]++; 53 printf("%d\n",s.size()); 54 } 55 for (int i=1;i<t1;i++) 56 printf("%d ",name[i]); 57 printf("%d\n",name[t1]); 58 } 59 60 int cmp(int *r,int x,int y,int l) 61 { 62 return (r[x]==r[y] && r[x+l]==r[y+l]); 63 } 64 65 void da(int n,int m,int *ws) 66 { 67 int i,j,p,*x=wa,*y=wb,*t; 68 for (i=0;i<m;i++) ws[i]=0; 69 for (i=0;i<n;i++) ws[x[i]=r[i]]++; 70 for (i=1;i<m;i++) ws[i]+=ws[i-1]; 71 for (i=n-1;i>=0;i--) sa[--ws[x[i]]]=i; 72 for (p=1,j=1;p<n;j*=2,m=p) 73 { 74 for (p=0,i=n-j;i<n;i++) y[p++]=i; 75 for (i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j; 76 for (i=0;i<n;i++) wv[i]=x[y[i]]; 77 for (i=0;i<m;i++) ws[i]=0; 78 for (i=0;i<n;i++) ws[wv[i]]++; 79 for (i=1;i<m;i++) ws[i]+=ws[i-1]; 80 for (i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i]; 81 for (t=x,x=y,y=t,p=1,i=1,x[sa[0]]=0;i<n;i++) 82 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 83 } 84 } 85 86 void callheight(int n) 87 { 88 int i,j,k=0; 89 for (i=1;i<=n;i++) rank[sa[i]]=i; 90 for (i=0;i<n;h[rank[i++]]=k) 91 for (k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); 92 } 93 94 void init() 95 { 96 scanf("%d %d",&t1,&t2); 97 n=-1; 98 for (int i=1;i<=t1;i++) 99 { 100 scanf("%d",&x); 101 for (int j=0;j<x;j++) //xing 102 { 103 scanf("%d",&y); 104 n++; 105 r[n]=y+3; 106 num[n]=i; 107 } 108 n++; 109 r[n]=0; 110 scanf("%d",&x); 111 for (int j=0;j<x;j++) //ming 112 { 113 scanf("%d",&y); 114 n++; 115 r[n]=y+3; 116 num[n]=i; 117 } 118 n++; 119 r[n]=0; //末尾结束符 120 } 121 maxlegal=n; 122 for (int i=1;i<=t2;i++) 123 { 124 scanf("%d",&x); 125 rec[i]=n+1; 126 q[i]=x; 127 for (int j=0;j<x;j++) 128 { 129 scanf("%d",&y); 130 n++; 131 r[n]=y+3; 132 num[n]=i+t1; 133 } 134 n++; 135 r[n]=0; 136 } 137 cnt=1; 138 r[n]=0; 139 da(n+1,maxm,wss); 140 callheight(n); 141 } 142 143 144 int main () 145 { 146 init(); 147 work(); 148 close(); 149 }