标签:
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> using namespace std; typedef __int64 LL; typedef pair<int,int> par; const int maxn=100005; char S[maxn]; int A[maxn]; LL sum[maxn]; int wa[maxn],wb[maxn],wv[maxn],WS[maxn],sa[maxn]; bool cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l]; } void DA(int *r,int n,int m) //模板 { int i,j,p; int *x=wa,*y=wb; 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(p=1,j=1;p<n;j<<=1,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]; swap(x,y); for(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 rk[maxn],h[maxn]; void GetHeight(int *r,int n) { for(int i=0;i<=n;i++) rk[sa[i]]=i; int k=0; h[0]=0; for(int i=0;i<n;i++) { if(k) k--; //先减1 int j=sa[rk[i]-1];//排名在前面的 while(r[i+k]==r[j+k]) k++; //相同一直加 h[rk[i]]=k; } } int BIS(int x,int y,LL k)//找到第一个大于k的位置 { while(x<=y) { int mid=(x+y)/2; if(sum[mid]>=k) y=mid-1; else x=mid+1; } return y+1; } int main() { while(scanf("%s",S)!=EOF) { int len=strlen(S); for(int i=0;i<len;i++) A[i]=S[i]; A[len]=0; DA(A,len+1,130); //后缀数组处理 GetHeight(A,len); //得到lcp值 sum[0]=0; for(int i=1;i<=len;i++) { int a=sa[i]; int b=h[i]; sum[i]=sum[i-1]+len-a-b; //计算不同子串个数 } int Q; LL l=0,r=0,v; scanf("%d",&Q); while(Q--) { scanf("%lld",&v); LL k=(l^r^v)+1; if(k>sum[len]) printf("%lld %lld\n",l=0,r=0); //无解的情况 else { int p=BIS(1,len,k); //二分找 l=sa[p]; int sl=h[p]+k-sum[p-1]; //长度 int cur=p; while(++cur<=len&&h[cur]>=sl) l=min(l,(LL)sa[cur]);//往后面找位置最小的,不知道这种方式为何不会超时 r=l+sl-1; l++; r++; printf("%lld %lld\n",l,r); } } } return 0; }
Hdu5008-Boring String Problem(后缀数组)
标签:
原文地址:http://www.cnblogs.com/wust-ouyangli/p/5745626.html