(我並不想告訴你題目名字是什麼鬼)c++
有一個長度爲n的僅包含小寫字母的字符串S,下標範圍爲[1,n].數組
如今有若干組詢問,對於每個詢問,咱們給出若干個後綴(以其在S中出現的起始位置來表示),求這些後綴兩兩之間的LCP(LongestCommonPrefix)的長度之和.一對後綴之間的LCP長度僅統計一遍測試
第一行兩個正整數n,m,分別表示S的長度以及詢問的次數.ui
接下來一行有一個字符串S.spa
接下來有m組詢問,對於每一組詢問,均按照如下格式在一行內給出:code
首先是一個整數t,表示共有多少個後綴.接下來t個整數分別表示t個後綴在字符串S中的出現位置排序
對於每一組詢問,輸出一行一個整數,表示該組詢問的答案.因爲答案可能很大,僅須要輸出這個答案對於23333333333333333(一個巨大的質數)取模的餘數.ip
7 3字符串
popoqqqinput
1 4
2 3 5
4 1 2 5 6
0
0
2
### Hint
樣例解釋:
對於詢問一,只有一個後綴」oqqq」,所以答案爲0.
對於詢問二,有兩個後綴」poqqq」以及」qqq」,兩個後綴之間的LCP爲0,所以答案爲0.
對於詢問三,有四個後綴」popoqqq」,」opoqqq」,」qqq」,」qq」,其中只有」qqq」,」qq」兩個後綴之間的LCP不爲0,且長度爲2,所以答案爲2.
對於100%的測試數據,有\(S<=5*10^5\),且\(\sum t<=3*10^6\).
特別注意:因爲另外一世界線的某些參數發生了變化,對於一組詢問,即便一個後綴出現了屢次,也僅算一次.
首先一個很顯然的思路就是直接把這個數組按照rank排序,而後咱們發現對於每一個點,前面的點的貢獻從前日後是單調不減的,而後就能夠直接維護單調棧了
挺水的題
#include<bits/stdc++.h> using namespace std; typedef pair<int, int> pi; typedef long long ll; const int N = 5e5 + 10; const int M = 3e6 + 10; const int LOG = 20; const ll Mod = 23333333333333333; struct Suffix_Array { int s[N], n, m; int c[N], x[N], y[N]; int height[N], sa[N], rank[N]; int st[N][LOG], Log[N]; ll sum[N]; void init(int len, char *c) { n = len, m = 0; for (int i = 1; i <= len; i++) { s[i] = c[i]; m = max(m, s[i]); } } void radix_sort() { for (int i = 1; i <= m; i++) c[i] = 0; for (int i = 1; i <= n; i++) c[x[y[i]]]++; for (int i = 1; i <= m; i++) c[i] += c[i - 1]; for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i]; } void buildsa() { for (int i = 1; i <= n; i++) x[i] = s[i], y[i] = i; radix_sort(); int now; for (int k = 1; k <= n; k <<= 1) { now = 0; for (int i = n - k + 1; i <= n; i++) y[++now] = i; for (int i = 1; i <= n; i++) if (sa[i] > k) y[++now] = sa[i] - k; radix_sort(); y[sa[1]] = now = 1; for (int i = 2; i <= n; i++) y[sa[i]] = (x[sa[i]] == x[sa[i - 1]] && x[sa[i] + k] == x[sa[i - 1] + k]) ? now : ++now; swap(x, y); if (now == n) break; m = now; } } void buildrank() { for (int i = 1; i <= n; i++) rank[sa[i]] = i; } void buildsum() { for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + n - sa[i] + 1 - height[i]; } void buildheight() { for (int i = 1; i <= n; i++) if (rank[i] != 1) { int k = max(height[rank[i - 1]] - 1, 0); // 裏面是 rank[i - 1] for (; s[i + k] == s[sa[rank[i] - 1] + k]; k++); height[rank[i]] = k; // height 裏面是 rank } } void buildst() { Log[1] = 0; for (int i = 2; i < N; i++) Log[i] = Log[i >> 1] + 1; for (int i = 1; i <= n; i++) st[i][0] = height[i]; for (int j = 1; j < LOG; j++) { for (int i = 1; i + (1 << (j - 1)) <= n; i++) { st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); } } } int queryst(int l, int r) { if (l == r) return n - sa[l] + 1; if (l > r) swap(l, r); ++l; //*** int k = Log[r - l + 1]; return min(st[l][k], st[r - (1 << k) + 1][k]); } int querylcp(int la, int lb) { return queryst(rank[la], rank[lb]); } void build(int len, char *c) { init(len, c); buildsa(); buildrank(); buildheight(); buildsum(); buildst(); } } Sa; int n, q, m; char c[N]; ll ans, sum; pi p[M]; struct Node { int num, pos; ll val; }; stack<Node> Q; ll add(ll a, ll b) { return (a += b) >= Mod ? a - Mod : a; } int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif scanf("%d %d", &n, &q); scanf("%s", c + 1); Sa.build(n, c); while (q--) { scanf("%d", &m); for (int i = 1; i <= m; i++) { scanf("%d", &p[i].second); p[i].first = Sa.rank[p[i].second]; } sort(p + 1, p + m + 1); m = unique(p + 1, p + m + 1) - p - 1; ans = sum = 0; while (Q.size()) Q.pop(); Q.push((Node) {1, p[1].second, 0}); for (int i = 2; i <= m; i++) { int curnum = 1, len = Sa.querylcp(Q.top().pos, p[i].second); while (Q.size() && Q.top().val >= len) { curnum += Q.top().num; sum -= Q.top().val * Q.top().num; Q.pop(); } Q.push((Node) {curnum, p[i].second, len}); sum += len * curnum; ans = add(ans, sum); } printf("%lld\n", ans); } return 0; }