Jong Hyok and String
Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 301 Accepted Submission(s): 66
Total Submission(s): 301 Accepted Submission(s): 66
Problem Description
Jong Hyok loves strings. One day he gives a problem to his friend you. He writes down n strings Pi in front of you, and asks m questions. For i-th question, there is a string Qi. We called strange set(s)
= {(i, j) | s occurs in Pi and j is the position of its last character in the current occurence}. And for ith question, you must answer the number of different strings t which satisfies strange set(Qi) = strange set(t) and t is a substring of at least one
of the given n strings.
Input
First line contains T, a number of test cases.
For each test cases, there two numbers n, m and then there are n strings Pi and m strings Qj.(i = 1…n, j = 1…m)
1 <= T <= 10
1 <= n <= 100000
1 <= m<= 500000
1 <=|Pi|<=100000
1 <=|Qi|<=100000
∑
n
i=1
|P
i
|≤100000![]()
File size is less than 3.5 megabytes.
For each test cases, there two numbers n, m and then there are n strings Pi and m strings Qj.(i = 1…n, j = 1…m)
1 <= T <= 10
1 <= n <= 100000
1 <= m<= 500000
1 <=|Pi|<=100000
1 <=|Qi|<=100000
∑
File size is less than 3.5 megabytes.
Output
For each test case, first line contains a line “Case #x:”, x is the number of the case.
For each question, you should print one integer in one line.
For each question, you should print one integer in one line.
Sample Input
1 2 2 aba ab a ab
Sample Output
Case #1: 1 2Hintstrange set(“a”) ={(1, 1), (1, 3), (2, 1)}. strange set(“ab”) ={(1, 2), (2, 2)}. strange set(“b”) ={(1, 2), (2, 2)}.分析:考虑到P串长度总和为10w,我们把每个P串倒着连成一串,中间用特殊符隔开,由于特殊符号需要10w个,所以我们要把字符换成int,然后跑后缀数组,就可以得到每个后缀的排名,查询时也把Q串倒序,并换成int,然后去每个后缀里面找哪些可以和这个倒序的Q串匹配,由于每个后缀已经排好序,所以我们用二分查找得到下界lower和上界upper,如果找不到,那么答案就是0。先定义一个maxlen,如果lower==upper,那么maxlen为排名为lower的这个后缀的不包含特殊符的最大前缀,如果lower<upper,那么maxlen=min(height[lower+1]...height[upper]),这里取最小值可以用RMQ处理height值得到,然后最后的答案ans=maxlen-max(height[lower],height[upper+1])#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int N=200010; const int maxn=100010; int cmp(int *r,int a,int b,int l) { return (r[a]==r[b])&&(r[a+l]==r[b+l]); } int wa[N],wb[N],ws[N],wv[N]; int Rank[N],height[N]; void DA(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) ws[i]=0; for(i=0;i<n;i++) ws[x[i]=r[i]]++; for(i=1;i<m;i++) ws[i]+=ws[i-1]; for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p) { for(p=0,i=n-j;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++) wv[i]=x[y[i]]; for(i=0;i<m;i++) ws[i]=0; for(i=0;i<n;i++) ws[wv[i]]++; for(i=1;i<m;i++) ws[i]+=ws[i-1]; for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } int k=0; for(i=1;i<n;i++) Rank[sa[i]]=i; for(i=0;i<n-1; height[Rank[i++]] = k ) for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++); } char s[maxn]; int a[maxn]; int r[N],sa[N],C[N][20]; int pos[N]; void rmq(int nn) { for(int i=1;i<nn;i++) C[i][0]=height[i]; for(int j=1;(1<<j)<nn;j++) for(int i=1;i+(1<<j)-1<nn;i++) C[i][j]=min(C[i][j-1],C[i+(1<<(j-1))][j-1]); } int getmin(int l,int r) { int k=0; while((1<<(k+1))<=r-l+1) k++; return min(C[l][k],C[r-(1<<k)+1][k]); } int cmp(int pos,int len,int num) { for(int i=0;i<len;i++) { if(r[i+pos]>a[i]) return 1; else if(r[i+pos]<a[i]) return -1; } return 0; } int main() { int T; scanf("%d",&T); for(int ca=1;ca<=T;ca++) { int n,m; scanf("%d%d",&n,&m); int num=0; for(int i=1;i<=n;i++) { scanf("%s",s); int len=strlen(s); reverse(s,s+len); int mm=num+len-1; for(int j=0;j<len;j++) { pos[num]=mm; r[num++]=s[j]-'a'+1; } r[num++]=26+i; } r[num++]=0; DA(r,sa,num,n+27); height[num]=0; rmq(num); printf("Case #%d:\n",ca); while(m--) { scanf("%s",s); int len=strlen(s); reverse(s,s+len); for(int i=0;i<len;i++) a[i]=s[i]-'a'+1; int lower=-1,upper=-1; int L,R; L=1,R=num-1; while(L<=R) { int mid=(L+R)>>1; int k=cmp(sa[mid],len,num); if(k==0) { lower=mid; R=mid-1; } else if(k==1) R=mid-1; else L=mid+1; } L=1,R=num-1; while(L<=R) { int mid=(L+R)>>1; int k=cmp(sa[mid],len,num); if(k==0) { upper=mid; L=mid+1; } else if(k==1) R=mid-1; else L=mid+1; } if(lower==-1) { puts("0"); continue; } if(lower==upper) { printf("%d\n",(pos[sa[lower]]-sa[lower]+1)-max(height[lower],height[lower+1])); continue; } int ans=getmin(lower+1,upper)-max(height[lower],height[upper+1]); printf("%d\n",ans); } } return 0; }