CF 316G3 Good Substring SAM上的简单计数

来源:互联网 发布:如何关闭蜂窝移动数据 编辑:程序博客网 时间:2024/04/29 17:36

题目大意

给你一个长度为N的字符串SM个限制。每个限制为(t,l,r),表示限制字符串st中的出现次数为lr。问S中有多少不同的子串符合这M条限制。

N,Lenti500000
M10

解题思路

看到这题,一个很直接的思路就是用SAM来做,我们可以先建出S的SAM,然后再把M个限制串也放进去。SAM中每个节点i维护Fi,j表示含有tj的子串在这个状态的个数,那么最后我们对于fail树从下往上做,求出每个节点的答案,在维护每个节点父亲的值就可以了。

程序

//YxuanwKeith#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int MAXN = 6e5 + 5;struct SAM {    int Len, Pre, Go[27];} A[MAXN * 2];char S[MAXN];int N, Last, Root, tot, L[15], R[15], Ord[MAXN * 2], F[MAXN * 2][15];void Add(int ch, int Ord) {    int np = ++ tot, p = Last;    A[np].Len = A[p].Len + 1;    if (Ord != -1) F[np][Ord] ++;    for (; p && !A[p].Go[ch]; p = A[p].Pre) A[p].Go[ch] = np;    if (!p) A[np].Pre = Root; else {        int q = A[p].Go[ch];        if (A[q].Len == A[p].Len + 1) A[np].Pre = q; else {            int nq = ++ tot;            A[nq] = A[q];            A[nq].Len = A[p].Len + 1;            A[np].Pre = A[q].Pre = nq;            for (; p && A[p].Go[ch] == q; p = A[p].Pre) A[p].Go[ch] = nq;        }      }    Last = np;}void Sort() {    static int tax[MAXN];    memset(tax, 0, sizeof tax);    for (int i = 1; i <= tot; i ++) tax[A[i].Len] ++;    for (int i = 1; i < MAXN; i ++) tax[i] += tax[i - 1];    for (int i = tot; i; i --) Ord[tax[A[i].Len] --] = i;}void Solve() {    int Ans = 0;    for (int i = tot; i; i --) {        int Now = Ord[i];        for (int j = 0; j <= N; j ++) F[A[Now].Pre][j] += F[Now][j];        if (!F[Now][0]) continue;        bool Flag = 1;        for (int j = 1; j <= N; j ++)             if (F[Now][j] < L[j] || F[Now][j] > R[j]) Flag = 0;        if (Flag) Ans += A[Now].Len - A[A[Now].Pre].Len;     }    printf("%d\n", Ans);}int main() {    scanf("%s", S + 1);    Root = tot = Last = 1;    for (int i = 1; i <= strlen(S + 1); i ++) Add(S[i] - 'a', 0);    Add(26, -1);    scanf("%d", &N);    for (int i = 1; i <= N; i ++) {        scanf("%s%d%d\n", S + 1, &L[i], &R[i]);        for (int j = 1; j <= strlen(S + 1); j ++) Add(S[j] - 'a', i);        Add(26, -1);    }    Sort();    Solve();}
1 0
原创粉丝点击