HDU 5008 Boring String Problem

题意:给定一个串长度<=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: >>>>>>>>>>>>>>>
", (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
", lans, rans);
148         }
149     }
150     return 0;
151 }
View Code
原文地址:https://www.cnblogs.com/rootial/p/3974072.html