题意:给定一个串长度<=1e5,将其所有的不同的字串按照字典序排序,然后q个询问,每次询问字典序第k小的的起始坐标,并且起始坐标尽量小。
分析:
一开始看错题意,没有意识到是求不同的字串中第k小的,果断不知道怎么做,感觉如果题目改成这样,似乎还有点难度,至少对我来说。
好了,这个题目是考虑不同的字串,首先后缀数组处理,也就是讲后缀按照字典序排序,对于每个后缀开始的字串,如h[i],容易知道i和i-1的后缀的LCP长度为h[i]那么i中除开前h[i]个字串,之后的字串在i-1之前都是没有出现过的,而且字典序要比之前的大,这样的字串数目时len-sa[i]-h[i],那么对于每个i用val[i]表示,sum[i]表示前i项的val值之和,对于第k小的字串,找到一个sum[i]>k,然后判断一下sum[i-1]是不是==k,不是的话说明第k小的字串一定在后缀i的字串中出现过,并算出长度L。然后再确定其在整个字符串中出现的最左位置,L>h[i]显然成立,所以L只能在i之后的后缀的字串中出现,找到一个范围i~r,使得之间的h值>=L,然后RMQ求出最小的sa值,也就是字串出现的最左位置。
话说暴力查找最左位置,竟然也能水过,而且速度还有快,测试数据里面肯定没有10000个a,每次询问第1小的字串这组数据。
考虑相同的字串,询问第k小的怎么做?
代码:
1 #include <cstdio> 2 #include <iostream> 3 #include <vector> 4 #include <algorithm> 5 #define inf 0x0f0f0f0f 6 #define pb push_back 7 #define bug(x) printf("line %d: >>>>>>>>>>>>>>>\n", (x)); 8 #define in freopen("F:\\code\\data\\data.txt", "r", stdin); 9 #define out freopen("F:\\code\\data\\data_out.txt", "w", stdout); 10 11 #define SZ(x) ((int)x.size()) 12 #define lson rt<<1, l, m 13 #define rson rt<<1|1, m+1, r 14 #define fi first 15 #define se second 16 using namespace std; 17 typedef long long LL; 18 const int maxn = (int)1e5 + 100; 19 int s[maxn], sa[maxn], t[maxn], t2[maxn], rk[maxn], h[maxn], c[maxn]; 20 int n, m; 21 LL lans, rans; 22 LL sum[maxn], val[maxn]; 23 24 void buildSa(int m) 25 { 26 int *x = t, *y = t2; 27 for(int i = 0; i < m; i++) c[i] = 0; 28 for(int i = 0; i < n; i++) c[x[i]=s[i]]++; 29 30 for(int i = 1; i < m; i++) c[i] += c[i-1]; 31 for(int i = n-1; i >= 0; i--) sa[--c[x[i]]] = i; 32 33 for(int k = 1; k <= n; k <<= 1) 34 { 35 int p = 0; 36 for(int i = n-k; i < n; i++) y[p++] = i; 37 for(int i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k; 38 39 for(int i = 0; i < m; i++) c[i] = 0; 40 for(int i = 0; i < n; i++) c[x[i]]++;// 41 for(int i = 1; i < m; i++) c[i] += c[i-1]; 42 for(int i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; 43 44 p = 1; 45 swap(x, y); 46 x[sa[0]] = 0; 47 48 for(int i = 1; i < n; i++) 49 x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p-1 : p++; 50 m = p; 51 if(p >= n) 52 break; 53 } 54 } 55 void getHeight() 56 { 57 int k = 0, j; 58 h[0] = 0; 59 for(int i = 0; i < n; i++) rk[sa[i]] = i; 60 for(int i = 0; i < n; i++) 61 { 62 if(k) k--; 63 if(rk[i] == 0) 64 continue; 65 j = sa[rk[i]-1]; 66 while(s[i+k] == s[j+k]) 67 k++; 68 h[rk[i]] = k; 69 } 70 } 71 int dp[maxn][20], mx[maxn][20]; 72 void rmqInit(int a[][20], int h[]) 73 { 74 for(int i = 0; i < n; i++) a[i][0] = i; 75 for(int k = 1; (1<<k) <= n; k++) 76 for(int i = 0; i + (1<<k) <= n; i++) 77 a[i][k] = h[a[i][k-1]] < h[a[i+(1<<(k-1))][k-1]] ? a[i][k-1] : a[i+(1<<(k-1))][k-1]; 78 } 79 int RMQ(int l, int r, int a[][20], int h[]) 80 { 81 if(l > r) swap(l, r); 82 int k = 0; 83 while((1<<(k+1)) < r-l+1) k++; 84 return h[a[l][k]] < h[a[r-(1<<k)+1][k]] ? a[l][k] : a[r-(1<<k)+1][k]; 85 } 86 char str[maxn]; 87 int check(int l, int r) 88 { 89 return h[RMQ(l, r, dp, h)]; 90 } 91 void solve(LL k) 92 { 93 if(k > sum[n-1]) 94 { 95 lans = rans = 0; 96 return; 97 } 98 int kk = upper_bound(sum+1, sum+n, k)-sum; 99 if(sum[kk-1] == k) 100 kk--; 101 k -= sum[kk-1]; 102 103 int len = h[kk]+k; 104 int x = sa[kk]; 105 if(kk+1 < n && h[kk+1] >= len) 106 { 107 int l = kk+1, r = n; 108 while(r-l > 1) 109 { 110 int mid = (l+r)>>1; 111 if(check(mid, kk+1) >= len) 112 l = mid; 113 else r = mid; 114 } 115 x = min(x, sa[RMQ(kk+1, l, mx, sa)]); 116 } 117 lans = x+1, rans = x+len; 118 } 119 int main() 120 { 121 122 123 while(scanf("%s", str) == 1) 124 { 125 n = 0; 126 for(int i = 0; str[i]; i++) 127 s[n++] = str[i]-'a'+1; 128 s[n++] = 0; 129 buildSa(30); 130 getHeight(); 131 rmqInit(dp, h); 132 rmqInit(mx, sa); 133 // bug(1) 134 int q; 135 lans = rans = 0; 136 for(int i = 1; i < n; i++) 137 { 138 val[i] = n-1-sa[i]-h[i]; 139 sum[i] = sum[i-1] + val[i]; 140 } 141 for(int t = scanf("%d", &q); t <= q; t++) 142 { 143 LL v; 144 scanf("%I64d", &v); 145 LL k = (lans^rans^v)+1; 146 solve(k); 147 printf("%I64d %I64d\n", lans, rans); 148 } 149 } 150 return 0; 151 }