本题要求第k小的distinct子串,可以根据height数组,二分出这个第k小子串所在后缀的位置信息。由于题目要求子串起始下标尽可能小。所以再在rank数组中,二分出与当前后缀LCP大于等于所求子串长度的范围。通过RMQ求出这个范围中最小的sa。
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 #include <string> 5 #include <string.h> 6 #include <stdio.h> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <set> 11 #include <cmath> 12 #include <ctime> 13 #include <cassert> 14 #include <sstream> 15 using namespace std; 16 17 const int N=123456; 18 19 int MIN(int a,int b){return a<b?a:b;} 20 int MAX(int a,int b){return a>b?a:b;} 21 22 int val[N]; 23 struct RMQ { 24 int dp[N][22]; 25 int (*cmp) (int,int); 26 void setMin(){cmp=MIN;} 27 void setMax(){cmp=MAX;} 28 void init(int n,int *val) { 29 for (int i=1; i<=n; i++) 30 dp[i][0]=val[i]; 31 for (int j=1; (1<<j)<=n; j++) { 32 int k=1<<(j-1); 33 for (int i=1; i+k<=n; i++) 34 dp[i][j]=cmp(dp[i][j-1],dp[i+k][j-1]); 35 } 36 } 37 int query(int a,int b) { 38 if (a>b) swap(a,b); 39 int dis=b-a+1; 40 int k=log((double)dis)/log(2.0); 41 return cmp(dp[a][k],dp[b-(1<<k)+1][k]); 42 } 43 }rmq; 44 char s[N]; 45 struct SuffixArray {; 46 int sa[N]; 47 int t1[N],t2[N],c[N]; 48 int rk[N],height[N]; 49 long long sum[N]; 50 inline int cmp(int *r,int a,int b,int l){ 51 return r[a]==r[b]&&r[a+l]==r[b+l]; 52 } 53 void calcSA (char *s,int n,int m) { 54 int i,j,p,*x=t1,*y=t2; 55 for(i=0;i<m;i++)c[i]=0; 56 for(i=0;i<n;i++)c[x[i]=s[i]]++; 57 for(i=1;i<m;i++)c[i]+=c[i-1]; 58 for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; 59 for(j=1;j<=n;j<<=1){ 60 p=0; 61 for(i=n-j;i<n;i++)y[p++]=i; 62 for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p 63 for(i=0;i<m;i++)c[i]=0; 64 for(i=0;i<n;i++)c[x[y[i]]]++; 65 for(i=1;i<m;i++)c[i]+=c[i-1]; 66 for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa 67 swap(x,y); 68 p=1;x[sa[0]]=0; 69 for(i=1;i<n;i++) 70 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 71 if(p>=n)break; 72 m=p; 73 } 74 } 75 void calcHeight(char *s,int n) { 76 int i,j,k=0; 77 for(i=0;i<=n;i++)rk[sa[i]]=i; 78 for(i=0;i<n;i++){ 79 if(k)k--; // h[i]>=h[i-1]-1 80 j=sa[rk[i]-1]; // suffix(j)排名在suffix(i)前一位 81 while(s[i+k]==s[j+k])k++; // 暴力计算lcp 82 height[rk[i]]=k; 83 } 84 sum[0]=0; 85 for (int i=1;i<=n;i++) sum[i]=sum[i-1]+n-sa[i]-height[i]; 86 } 87 int lcp(int a,int b,int len) { 88 if (a==b) return len-a; 89 int ra=rk[a],rb=rk[b]; 90 if (ra>rb) swap(ra,rb); 91 return queryST(ra+1,rb); 92 } 93 int st[N][25]; 94 void initST(int n) { 95 for (int i=1;i<=n;i++) 96 st[i][0]=height[i]; 97 for (int j=1;(1<<j)<=n;j++) { 98 int k=1<<(j-1); 99 for (int i=1; i+k<=n; i++) 100 st[i][j]=min(st[i][j-1],st[i+k][j-1]); 101 } 102 } 103 int queryST(int a,int b) { 104 if (a>b) swap(a,b); 105 int dis=b-a+1; 106 int k=log((double)dis)/log(2.0); 107 return min(st[a][k],st[b-(1<<k)+1][k]); 108 } 109 void solve(int &l,int &r,long long k,int n) { 110 if (k<1||k>sum[n]) { 111 l=0;r=0; 112 return; 113 } 114 int t=lower_bound(sum,sum+n+1,k)-sum; 115 assert(t>=1&&t<=n); 116 long long now=sum[t-1]; 117 int need=k-now; 118 l=sa[t],r=sa[t]+height[t]+need-1; 119 int len=r-l+1; 120 int le=t,ri=n,ret=l; 121 while (le<=ri) { 122 int mid=(le+ri)/2; 123 if (lcp(sa[mid],l,n)>=len) { 124 le=mid+1; 125 ret=mid; 126 } else ri=mid-1; 127 } 128 l=rmq.query(t,ret); 129 l++; 130 r=l+len-1; 131 } 132 }suf; 133 134 int main () { 135 while (scanf("%s",s)!=EOF) { 136 int n=strlen(s); 137 suf.calcSA(s,n+1,128); 138 suf.calcHeight(s,n); 139 suf.initST(n); 140 rmq.setMin(); 141 rmq.init(n,suf.sa); 142 int Q; 143 scanf("%d",&Q); 144 int l=0,r=0; //int cnt=0; 145 while (Q--) { 146 long long k; 147 scanf("%I64d",&k); 148 k^=(l^r); 149 k++; 150 //k=++cnt; 151 suf.solve(l,r,k,n); 152 printf("%d %d\n",l,r); 153 } 154 } 155 return 0; 156 }