BZOJ 3230: 相似子串

3230: 相似子串

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 1485  Solved: 361
[Submit][Status][Discuss]

Description

 

Input

输入第1行,包含3个整数N,Q。Q代表询问组数。
第2行是字符串S。
接下来Q行,每行两个整数i和j。(1≤i≤j)。

 

Output

输出共Q行,每行一个数表示每组询问的答案。如果不存在第i个子串或第j个子串,则输出-1。

 

Sample Input

5 3
ababa
3 5
5 9
8 10

Sample Output

18
16
-1

HINT

 

样例解释

第1组询问:两个子串是“aba”,“ababa”。f = 32 + 32 = 18。

第2组询问:两个子串是“ababa”,“baba”。f = 02 + 42 = 16。

第3组询问:不存在第10个子串。输出-1。


数据范围

N≤100000,Q≤100000,字符串只由小写字母'a'~'z'组成

 

Source

[Submit][Status][Discuss]

 

Source里说的十分清楚了,题目本身也很水。

求出后缀数组,再把字符串reverse后求出“前缀数组”。

通过后缀数组可以对子串按排名进行定位,然后查询正反LCP即可。

 

  1 #include <bits/stdc++.h>
  2 
  3 template <class T>
  4 T sqr(T x)
  5 {
  6     return x*x;
  7 }
  8 
  9 typedef long long longint;
 10 
 11 const int maxn = 100005;
 12 const longint inf = 1e9;
 13 
 14 int n, m; 
 15 char s[maxn];
 16 longint g[maxn];
 17 longint pre[maxn];
 18 
 19 class SuffixArray
 20 {
 21 public:
 22     int sa[maxn], rk[maxn], ht[maxn];
 23 
 24     inline void init(void)
 25     {
 26         memset(ca, 0, sizeof(ca));
 27 
 28         for (int i = 1; i <= n; ++i)
 29             ++ca[s[i]];
 30 
 31         for (int i = 1; i <= 300; ++i)
 32             ca[i] += ca[i - 1];
 33 
 34         for (int i = n; i >= 1; --i)
 35             sa[ca[s[i]]--] = i;
 36 
 37         rk[sa[1]] = 1;
 38 
 39         for (int i = 2; i <= n; ++i)
 40             rk[sa[i]] = rk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]);
 41 
 42         for (int l = 1; rk[sa[n]] < n; l <<= 1)
 43         {
 44             memset(ca, 0, sizeof(ca));
 45             memset(cb, 0, sizeof(cb));
 46 
 47             for (int i = 1; i <= n; ++i)
 48             {
 49                 ++ca[wa[i] = rk[i]];
 50                 ++cb[wb[i] = i + l <= n ? rk[i + l] :0];
 51             }
 52             
 53             for (int i = 1; i <= n; ++i)
 54             {
 55                 ca[i] += ca[i - 1];
 56                 cb[i] += cb[i - 1];
 57             }
 58 
 59             for (int i = n; i >= 1; --i)
 60                 ta[cb[wb[i]]--] = i;
 61 
 62             for (int i = n; i >= 1; --i)
 63                 sa[ca[wa[ta[i]]]--] = ta[i];
 64 
 65             rk[sa[1]] = 1;
 66 
 67             for (int i = 2; i <= n; ++i)    
 68                 rk[sa[i]] = rk[sa[i - 1]] + (wa[sa[i]] != wa[sa[i - 1]] || wb[sa[i]] != wb[sa[i - 1]]);
 69         }
 70 
 71         for (int i = 1, j = 0; i <= n; ++i)
 72         {
 73             if (--j < 0)j = 0;
 74             while (s[i + j] == s[sa[rk[i] - 1] + j])++j;
 75             ht[rk[i]] = j;
 76         }
 77         
 78         build(1, 1, n);
 79     }
 80 
 81     inline int lcp(int a, int b)
 82     {
 83         a = rk[a];
 84         b = rk[b];
 85 
 86         if (a > b)
 87         {
 88             a ^= b;
 89             b ^= a;
 90             a ^= b;
 91         }
 92 
 93         return query(1, 1, n, a + 1, b);
 94     }
 95 private:
 96     void build(int t, int l, int r)
 97     {
 98         if (l == r)
 99             tr[t] = ht[l];
100         else
101         {
102             int mid = (l + r) >> 1;
103             build(t << 1, l, mid);
104             build(t << 1 | 1, mid + 1, r);
105             tr[t] = std::min(tr[t << 1], tr[t << 1 | 1]);
106         }
107     }
108     
109     int query(int t, int l, int r, int a, int b)
110     {
111         if (l == a && r == b)
112             return tr[t];
113         else
114         {
115             int mid = (l + r) >> 1;
116             if (b <= mid)
117                 return query(t << 1, l, mid, a, b);
118             else if (a > mid)
119                 return query(t << 1 | 1, mid + 1, r, a, b);
120             else
121                 return std::min(query(t << 1, l, mid, a, mid), query(t << 1 | 1, mid + 1, r, mid + 1, b));
122         }
123     }
124     
125     int ta[maxn], wa[maxn], wb[maxn], ca[maxn], cb[maxn], tr[maxn << 2];
126 }A, B;
127 
128 signed main(void)
129 {
130     scanf("%d%d%s", &n, &m, s + 1); 
131 
132     g[0] = -1;
133 
134     for (int i = 1; i <= n; ++i)
135         g[i] = g[i >> 1] + 1;
136 
137     A.init();
138     std::reverse(s + 1, s + 1 +n);
139     B.init();
140 
141     pre[0] = 0;
142 
143     for (int i = 1; i <= n; ++i)
144         pre[i] = pre[i - 1] + n - A.sa[i] + 1 - A.ht[i];
145         
146     for (int i = 1; i <= m; ++i)
147     {
148         longint lt, rt; scanf("%lld%lld", &lt, &rt);
149     
150         if (lt > pre[n] || rt > pre[n])
151             { puts("-1"); continue; }
152         
153         int id1, id2, a1, b1, a2, b2;
154         
155         id1 = std::lower_bound(pre + 1, pre + 1 + n, lt) - pre;
156         id2 = std::lower_bound(pre + 1, pre + 1 + n, rt) - pre;
157         
158         a1 = A.sa[id1];
159         a2 = A.sa[id2];
160         
161         b1 = a1 + A.ht[id1] - 1 + lt - pre[id1 - 1];
162         b2 = a2 + A.ht[id2] - 1 + rt - pre[id2 - 1];
163         
164         longint ans = 0, tmp;
165 
166         tmp = a1 == a2 ? inf : A.lcp(a1, a2);
167         tmp = std::min(tmp, (longint)std::min(b1 - a1 + 1, b2 - a2 + 1));
168 
169         ans += sqr(tmp);
170 
171         tmp = b1 == b2 ? inf : B.lcp(n - b1 + 1, n - b2 + 1);
172         tmp = std::min(tmp, (longint)std::min(b1 - a1 + 1, b2 - a2 + 1));
173 
174         ans += sqr(tmp);
175 
176         printf("%lld\n", ans);
177     }
178 }

 

@Author: YouSiki

posted @ 2016-12-21 21:27  YouSiki  阅读(400)  评论(0编辑  收藏  举报