K-string HDU - 4641 (后缀自动机)

K-string

\[ Time Limit: 2000 ms\quad Memory Limit: 131072 kB \]

题意

给出长度为 \(n\) 的字符串,接下来跟着 \(m\) 次操作,每次 \(1\) 操作往字符串末尾加一个 \(char\)\(2\) 操作统计字符串中出现次数 \(\geq K\) 的字符串个数。

思路

统计一个字符串出现个数,可以用 \(dp[father] = \sum dp[u]\),来计算,那么我们可以知道,一个点从本身往根跑的过程,这个 \(dp\) 值是一直在增大的,所以只要跑到某一个地方的 \(dp \geq K\),就可以不往上更新了,这样插入一个字符,更新一次,边更新边统计答案就可以了。(数据比较水,这样暴力在全是 \(a\) 的情况下是会 \(T\) 的)
这题我用结构体数组写 \(sam\) 被卡了,最后换了纯数组的 \(sam\)\(emmm\)

/***************************************************************
    > File Name    : a.cpp
    > Author       : Jiaaaaaaaqi
    > Created Time : 2019年06月06日 星期四 00时14分49秒
 ***************************************************************/

#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pii        pair<int, int>

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 5e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;

struct Sam {
    int node[maxn][27], fa[maxn], step[maxn];
    int dp[maxn];
    int sz, last, K, ans;
    int newnode() {
        mes(node[++sz], 0);
        fa[sz] = step[sz] = 0;
        dp[sz] = 0;
        return sz;
    }
    void init() {
        ans = sz = 0;
        last = newnode();
    }
    void insert(int k) {
        int p = last, np = last = newnode();
        step[np] = step[p]+1;
        for(; p&&!node[p][k]; p=fa[p])
            node[p][k] = np;
        if(p==0) {
            fa[np] = 1;
        } else {
            int q = node[p][k];
            if(step[q] == step[p]+1) {
                fa[np] = q;
            } else {
                int nq = ++sz;
                memcpy(node[nq], node[q], sizeof(node[q]));
                dp[nq] = dp[q];
                fa[nq] = fa[q];
                step[nq] = step[p]+1;
                fa[np] = fa[q] = nq;
                for(; p&&node[p][k]==q; p=fa[p])
                    node[p][k] = nq;
            }
        }
    }
    void update(int p) {
        for(; p&&dp[p]<K; p=fa[p]) {
            dp[p]++;
            if(dp[p]>=K)    ans+=step[p]-step[fa[p]];
        }
    }
} sam;
char s[50005];

int main() {
    while(~scanf("%d%d%d", &n, &m, &sam.K)) {
        scanf("%s", s+1);
        sam.init();
        int len = strlen(s+1);
        for(int i=1; i<=len; i++) {
            sam.insert(s[i]-'a'+1);
            sam.update(sam.last);
        }
        char ss[5];
        while(m--) {
            int id;
            scanf("%d", &id);
            if(id == 1) {
                scanf("%s", ss+1);
                sam.insert(ss[1]-'a'+1);
                sam.update(sam.last);
            } else {
                printf("%d\n", sam.ans);
            }
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Jiaaaaaaaqi/p/10987439.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值