3230: 相似子串
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 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
ababa
3 5
5 9
8 10
Sample Output
18
16
-1
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
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", <, &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 ", ans); 177 } 178 }
@Author: YouSiki