Problem J
L-Gap Substrings
Input:StandardInput
Output: Standard Output
If a string is in the form UVU, where Uis not empty, and V has exactly L characters, we say UVUis an L-Gap string. For example, abcbabc is a 1-Gapstring. xyxyxyxyxy is both a 2-Gap string and also a 6-Gapstring, but not a 10-Gap string (because U is non-empty).
Given a string s, and a positiveinteger g, you are to find the number of g-Gap substrings in s.s contains lower-case letters only, and has at most 50,000characters.
Thefirst line contains a single integer t(1<=t<=10), the number oftest cases. Each of the t followings contains an integer g(1<=g<=10)followed bya string s.
For each test case, print thecase number and the number of g-Gapsubstrings. Look at the output for sample input for details.
2 1 bbaabaaaaa 5 abxxxxxab |
Case 1: 7 Case 2: 1
|
给出L和一个串,输出格式为UVU的有多少个,V的长度为L。
做法和POJ3693类似。枚举U的长度i和UVU这个串的起始位置j,起始位置不是一个一个枚举,而是0,i,2*i...这样枚举。RMQ求出j和j+i+L位置的LCP,从j-L+1...j这一段处理方法是倒着求j-1和j+i+L-1的LCP(先把整个串在后面倒着复制一遍就是正着求对应位置的)。设sum=min(RMQ(sa.rank[j],sa.rank[j+i+L]),i)+min(RMQ(sa.rank[sa.n-j-1],sa.rank[sa.n-j-i-L-1]),i-1),那么以j-L+1...j起始的U长度为i的符合条件的串共有max(0,sum-i+1)个,自己画画就知道了。这样的时间复杂度(n+n/2+n/3...+1),为nlnn.
#include<iostream> #include<queue> #include<cstring> #include<cstdio> #include<cmath> #include<set> #include<map> #include<vector> #include<stack> #include<algorithm> using namespace std; typedef long long LL; typedef pair<LL,LL> pii; const int MAXN=50010*2; const int MAXNODE=4*MAXN; const int LOGMAXN=50; int T,L,d[MAXN][LOGMAXN]; char str[MAXN]; struct SuffixArray{ int s[MAXN]; int c[MAXN]; int sa[MAXN]; int height[MAXN]; int rank[MAXN]; int t[MAXN],t2[MAXN]; int n; void clear(){ n=0; memset(sa,0,sizeof(sa)); } void build_sa(int m){ int i,*x=t,*y=t2; for(i=0;i<m;i++) c[i]=0; for(i=0;i<n;i++) c[x[i]=s[i]]++; for(i=1;i<m;i++) c[i]+=c[i-1]; for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(int k=1;k<n;k<<=1){ int p=0; for(i=n-k;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(i=0;i<m;i++) c[i]=0; for(i=0;i<n;i++) c[x[y[i]]]++; for(i=1;i<m;i++) c[i]+=c[i-1]; for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n) break; m=p; } } void build_height(){ int k=0; for(int i=0;i<n;i++) rank[sa[i]]=i; height[0]=0; for(int i=0;i<n-1;i++){ if(k) k--; int j=sa[rank[i]-1]; while(s[i+k]==s[j+k]) k++; height[rank[i]]=k; } } }sa; void RMQ_init(){ for(int i=0;i<sa.n;i++) d[i][0]=sa.height[i]; for(int j=1;(1<<j)<=sa.n;j++) for(int i=0;i+(1<<j)<=sa.n;i++) d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } int RMQ(int L,int R){ if(L>=R) swap(L,R); L++; int k=0; while((1<<(k+1))<=R-L+1) k++; return min(d[L][k],d[R-(1<<k)+1][k]); } void solve(int len){ int ans=0; for(int i=1;i<=len/2;i++) for(int j=0;j<len;j+=i){ int sum=0; if(j+i+L<len) sum=min(RMQ(sa.rank[j],sa.rank[j+i+L]),i); if(sa.n-j-i-L-1>=0) sum+=min(RMQ(sa.rank[sa.n-j-1],sa.rank[sa.n-j-i-L-1]),i-1); ans+=max(0,sum-i+1); } printf("%d\n",ans); } int main(){ freopen("in.txt","r",stdin); int cas=0; scanf("%d",&T); while(T--){ scanf("%d%s",&L,str); sa.clear(); int len=strlen(str); for(int i=0;i<len;i++) sa.s[sa.n++]=str[i]-'a'+1; sa.s[sa.n++]=27; for(int i=len-1;i>=0;i--) sa.s[sa.n++]=str[i]-'a'+1; sa.s[sa.n++]=0; sa.build_sa(30); sa.build_height(); RMQ_init(); //for(int i=0;i<sa.n;i++) printf("i=%d %d\n",i,sa.height[i]); printf("Case %d: ",++cas); solve(len); } return 0; }