hdu 4641 K-string SAM理解

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4641

题意:有一个长度不超过5e4的字符串,Q(Q<=2e5)次操作;

操作分为:1 ch 想字符串末尾插入一个字符ch; 2 表示查询目前的字符串中子串出现次数不小于k次的不同子串数目;

思路:SAM在线求解;

对于每次找到将一个字符x插入到SAM之后,我们知道pre[p]所含有的Tx的后缀字符串数目为step[pre[np]]个,那么只需要每次插入之后更新下这些字符串出现的次数cnt即可;

由于Right(fa)与Right(r)没有交集(max(fa) = min(r) - 1),所以需要一直递推到root,但是root不能计算,因为root并没有表示后缀,只是一个init状态;

还有一点就是在拷贝q的信息到nq中时,主要把cnt的信息也拷贝过去;

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

#define maxn 100007
#define SIGMA_SIZE 26

struct SAM{
    int sz,tot,last,k;
    int g[maxn<<1][SIGMA_SIZE],pre[maxn<<1],step[maxn<<1];
    int vs[maxn<<1],cnt[maxn<<1];

    void newNode(int s){
        step[++sz] = s;
        pre[sz] = 0;
        vs[sz] = cnt[sz] = 0;
        memset(g[sz],0,sizeof(g[sz]));
    }

    void init(){
        tot = 0;
        sz = 0; last = 1;
        newNode(0);
    }

    int idx(char ch){return ch - ‘a‘;}

    void Insert(char ch){
        newNode(step[last]+1);
        int v = idx(ch), p = last, np = sz;

        while(p && !g[p][v])
            g[p][v] = np,p = pre[p];    //知道找到Right集合中包含x的边的祖宗节点

        if(p){
            int q = g[p][v];
            if(step[q] == step[p] + 1)
                pre[np] = q;
            else{
                newNode(step[p]+1);
                int nq = sz;             //nq替换掉q节点
                for(int i = 0;i < SIGMA_SIZE;i++)
                    g[nq][i] = g[q][i];

                cnt[nq] = cnt[q];     //**
                pre[nq] = pre[q];
                pre[np] = pre[q] = nq;

                while(p && g[p][v] == q)
                    g[p][v] = nq,p = pre[p];
            }
        }
        else pre[np] = 1;
        for(int aux = np;aux != 1 && !vs[aux];aux = pre[aux]){
            if(++cnt[aux] >= k){
                tot += step[aux] - step[pre[aux]];
                vs[aux] = true;    //该父节点的子串已经加到tot中
            }
        }
        last = np;
    }
}SA;
char str[maxn];
int main()
{
    int n,Q;
    while(scanf("%d%d%d",&n,&Q,&SA.k) == 3){
        scanf("%s",str);
        SA.init();
        int len = strlen(str);
        for(int i = 0;i < len;i++){
            SA.Insert(str[i]);
        }
        int op;
        char ch[2];
        while(Q--){
            scanf("%d",&op);
            if(op & 1){
                scanf("%s",ch);
                SA.Insert(ch[0]);
            }
            else printf("%d\n",SA.tot);
        }
    }
}
时间: 2024-08-11 03:27:37

hdu 4641 K-string SAM理解的相关文章

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

题目链接:hdu 4641 K-string 题意: 一开始给你一个字符串S,现在有m个操作. 1 x表示在当前字符串末端添加一个字符x. 2 表示查询当前出现次数超过k次的子串有多少个. 题解: 后缀自动机在线维护right集. 没插入一个字符,就沿着fail跳,如果当前节点大于等于k的就不用再跳了,显然之前的节点肯定已经大于等于k了. 然后一旦有新的节点等于k就记录一下当前新增加的子串个数. 1 #include<cstdio> 2 #include<cstring> 3 #d

hdu 5008 Boring String Problem(后缀自动机构造后缀树)

hdu 5008 Boring String Problem(后缀自动机构造后缀树) 题意:给出一个字符串s,然后每次询问一个k,求s的所有子串中,字典序第k小的是谁?多个解,则输出最左边的那个 解题思路:这道题应该是为后缀树量身定制的吧.只要构造出了后缀树,然后按字典序遍历就可以得出每个节点包含的子串的字典序的范围了,而且必然是个连续的区间范围.但是我不会后缀树啊..比赛的时候突然想到,后缀自动机是可以构造后缀树的,虽然以前没写过,但还是硬着头皮上吧,居然还真的让我给撸出来了.我的做法是这样的

HDU 5008 Boring String Problem(西安网络赛B题)

HDU 5008 Boring String Problem 题目链接 思路:构造后缀数组,利用height的数组能预处理出每个字典序开始的前缀和有多少个(其实就是为了去除重复串),然后每次二分查找相应位置,然后在往前往后找一下sa[i]最小的 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int

hdu 5008 Boring String Problem(后缀数组)

题目链接:hdu 5008 Boring String Problem 题目大意:给定一个字符串,初始状态l,r为0,每次询问子串中字典序第l^r^v+1的子串区间,对于重复的输出下标小的. 解题思路:后缀数组,对给定字符串做后缀数组,然后根据height数组确定每个位置做为起点的子串有多少,然后二分查找确定起点位置,但是因为子串的重复的要输出下表小的,所以确定起点后还要确定字典序最小的下标. #include <cstdio> #include <cstring> #includ

Java中String的理解

Java中String的理解 最近在读String的源码,看了些String的文章,自己对String作了下总结记录下来. 1.String为什么是不可变的? String是final类,不可继承,其方法也不可被覆盖,避免从子类操纵父类属性:String的值保存在private final char[]数组中,本质是一个字符数组,私有则外部不可访问和修改,final引用则引用(或说引用的值)不变.引用可以简单地认为是堆上对象的首地址.String内部的private int hash,缓存has

Java String的理解

Java String的理解 在Java中String是一个比较特殊的对象---不可继承,不可变,直接赋值创建 不可继承,不可变 String 类型被标final关键字修饰,所以不可继承 public final class String implements java.io.Serializable, Comparable<String>, CharSequence { // .... } Sting类中提供了一个final修饰的字符数组,用于存储Sting类型的值,所以一旦初始化则不能修改

HDU 1708 Fibonacci String(数学题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1708 Problem Description After little Jim learned Fibonacci Number in the class , he was very interest in it. Now he is thinking about a new thing -- Fibonacci String . He defines : str[n] = str[n-1] + s

HDU 5311 Hidden String (优美的暴力)

Hidden String Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 52    Accepted Submission(s): 25 Problem Description Today is the 1st anniversary of BestCoder. Soda, the contest manager, gets a

HDU 1708 Fibonacci String(斐波那契字串)

Fibonacci String Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5358    Accepted Submission(s): 1819 Problem Description After little Jim learned Fibonacci Number in the class , he was very in