【题目链接】
【思路要点】
- 建立多串后缀树,依次考虑树上每一条边上代表的字符串是否应该被统计。
- 不妨设当前考虑的是节点 x x x与其父亲 f a t h e r father father的连边。
- 若节点 x x x满足子树内存在 S S S的结尾,并且子树内 p i p_i pi的结尾个数 c n t i cnt_i cnti满足 l i ≤ c n t x ≤ r i l_i≤cnt_x≤r_i li≤cntx≤ri,那么这条边上的字符串应当被计入答案,即 a n s = a n s + d e p t h f a t h e r − d e p t h x ans=ans+depth_{father}-depth_x ans=ans+depthfather−depthx,否则这条边上的字符串不被计入答案。
- 时间复杂度 O ( ∣ S ∣ + ∑ ∣ p i ∣ ) O(|S|+\sum|p_i|) O(∣S∣+∑∣pi∣)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 15; const int MAXL = 50005; const int MAXP = 1200005; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SuffixAutomaton { struct Node { int child[26]; int size[MAXN]; int father, depth; } a[MAXP]; char s[MAXL]; vector <int> b[MAXP]; int l[MAXL], r[MAXL]; int n, len, root, last, size; long long ans; int newnode(int dep) { a[size].depth = dep; return size++; } void extend(int ch, int col) { int p = last; if (!a[p].child[ch]) { int np = newnode(a[p].depth + 1); while (!a[p].child[ch]) { a[p].child[ch] = np; p = a[p].father; } if (a[p].child[ch] == np) last = np; else { int q = a[p].child[ch]; if (a[p].depth + 1 == a[q].depth) a[np].father = q, last = np; else { int nq = newnode(a[p].depth + 1); memcpy(a[nq].child, a[q].child, sizeof(a[q].child)); a[nq].father = a[q].father; a[q].father = a[np].father = nq; while (a[p].child[ch] == q) { a[p].child[ch] = nq; p = a[p].father; } last = np; } } } else { int q = a[p].child[ch]; if (a[p].depth + 1 == a[q].depth) last = q; else { int np = newnode(a[p].depth + 1); memcpy(a[np].child, a[q].child, sizeof(a[q].child)); a[np].father = a[q].father; a[q].father = np; while (a[p].child[ch] == q) { a[p].child[ch] = np; p = a[p].father; } last = np; } } a[last].size[col]++; } void init() { size = 0; last = root = newnode(0); scanf("\n%s", s + 1); len = strlen(s + 1); for (int i = 1; i <= len; i++) extend(s[i] - 'a', 0); read(n); for (int i = 1; i <= n; i++) { last = root; scanf("\n%s", s + 1); len = strlen(s + 1); for (int j = 1; j <= len; j++) extend(s[j] - 'a', i); read(l[i]), read(r[i]); } } void work(int pos) { for (unsigned i = 0; i < b[pos].size(); i++) { int tmp = b[pos][i]; work(tmp); for (int j = 0; j <= n; j++) a[pos].size[j] += a[tmp].size[j]; } if (pos) { bool flg = a[pos].size[0] != 0; for (int j = 1; j <= n; j++) flg &= a[pos].size[j] >= l[j] && a[pos].size[j] <= r[j]; ans += flg * (a[pos].depth - a[a[pos].father].depth); } } void calc() { for (int i = 1; i < size; i++) b[a[i].father].push_back(i); work(0); writeln(ans); } } SAM; int main() { SAM.init(); SAM.calc(); return 0; }

1533

被折叠的 条评论
为什么被折叠?



