HDU 6194 string string string(后缀自动机)

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=3238

【题目大意】

  给出一个字符串求其出现恰好k次的子串数量

【题解】

  对串建立AC自动机,所有right值为k的节点的value值的和就是答案

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=200010;
char s[N];
struct SAM{
    int p,q,np,nq,cnt,lst,a[N][26],l[N],f[N],tot;
    int Tr(char c){return c-‘a‘;}
    int val(int c){return l[c]-l[f[c]];}
    SAM(){cnt=0;lst=++cnt;}
    void Initialize(){
        memset(l,0,sizeof(int)*(cnt+1));
        memset(f,0,sizeof(int)*(cnt+1));
        for(int i=0;i<=cnt;i++)for(int j=0;j<26;j++)a[i][j]=0;
        cnt=0;lst=++cnt;
    }
    void extend(int c){
        p=lst;np=lst=++cnt;l[np]=l[p]+1;
        while(!a[p][c]&&p)a[p][c]=np,p=f[p];
        if(!p){f[np]=1;}
        else{
            q=a[p][c];
            if(l[p]+1==l[q])f[np]=q;
            else{
                nq=++cnt;l[nq]=l[p]+1;
                memcpy(a[nq],a[q],sizeof(a[q]));
                f[nq]=f[q]; f[np]=f[q]=nq;
                while(a[p][c]==q)a[p][c]=nq,p=f[p];
            }
        }
    }
    int b[N],x[N],r[N];
    void build(){
        scanf("%s",s+1);
        int len=strlen(s+1);
        for(int i=1;i<=len;i++)extend(Tr(s[i]));
        memset(r,0,sizeof(int)*(cnt+1));
        memset(b,0,sizeof(int)*(cnt+1));
        for(int i=1;i<=cnt;i++)b[l[i]]++;
        for(int i=1;i<=len;i++)b[i]+=b[i-1];
        for(int i=1;i<=cnt;i++)x[b[l[i]]--]=i;
        for(int i=p=1;i<=len;i++){p=a[p][Tr(s[i])];r[p]++;}
        for(int i=cnt;i;i--)r[f[x[i]]]+=r[x[i]];
    }
    void solve(){
        int ans=0,k;
        scanf("%d",&k);
        build();
        for(int i=1;i<=cnt;i++)if(r[x[i]]==k)ans+=val(x[i]);
        printf("%d\n",ans);
    }
}sam;
int T;
int main(){
    scanf("%d",&T);
    while(T--){
        sam.Initialize();
        sam.solve();
    }return 0;
}
时间: 2024-07-29 13:36:10

HDU 6194 string string string(后缀自动机)的相关文章

hdu 6194 string string string(后缀数组)

题目链接:hdu 6194 string string string 题意: 给你一个字符串,给你一个k,问你有多少个子串恰好在原串中出现k次. 题解: 后缀数组求出sa后,用height数组的信息去找答案. 每次用k长度的区间去卡height数组,求出该区间的lcp. 该区间的贡献就是ans=lcp-max(height[i],height[i+k]). 如果ans<=0,就不贡献. 比如 2 aaa 后缀数组为: 1 a 2 aa 3 aaa height为 0,1,2 现在扫到[1,2],

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

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

hdu 5853 Jong Hyok and String(广义后缀自动机)

题目链接:hdu 5853 Jong Hyok and String 题意: 给你n个字符串,m个询问,每次询问一个字符串 定义set(s)={(i,j)} 表示 s在第i个字符串中出现,且末尾位置为j. 对于一个询问,求set(Qi)=set(t) ,t串的数量. 题解: 如果是n=1,那么就是后缀自动机的一道裸题,答案就是Qi串匹配的最后一个节点x,ml[x]-ml[f[x]]. 现在是多个串,那么就建立一个广义后缀自动机.每次插入一个串后,将last=root,然后继续插下一个就行了. 最

[2018 ACM-ICPC 焦作赛区网络赛] H - String and Times(后缀自动机)

Now you have a string consists of uppercase letters, two integers AA and BB. We call a substring wonderful substring when the times it appears in that string is between AA and BB (A \le times \le BA≤times≤B). Can you calculate the number of wonderful

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the

hdu 5030 Rabbit&#39;s String(后缀数组)

题目链接:hdu 5030 Rabbit's String 题目大意:给定k和一个字符串,要求将字符串拆分成k个子串.然后将每个子串中字典序最大的子串选出来,组成一个包含k个字符串的集合,要求这个集合中字典序最大的字符串字典序最小. 解题思路:网赛的时候试图搞了一下这道题,不过水平还是有限啊,后缀数组也是初学,只会切一些水题.赛后看了一下别人的题解,把这题补上了. 首先对整个字符串做后缀数组,除了处理出sa,rank,height数组,还要处理处f数组,f[i]表示说以0~sa[i]开头共有多少

Hdu 5030 Rabbit&#39;s String (后缀数组)

题目大意: 要求将一个长串分解成最多k个子串,使得分开的n个串的字典序最大的那一个子串的字典序最小. 思路分析: 要最大的最小,不难想到二分的. 我们二分出原串中的第rk大子串就是目标串. 现在就是怎么判断这个串满足要求,也就是我们如何分其他部分,使之成为字典序最大的一个. 我们可以通过rk轻易的找到这是哪一个串,假设它处在sa[t]中. 那么可以知道 在 sa数组中t以前的子串的字典序都是比目标串小的. 而后面会有比sa大的,我们就要分解这些串. 我们从t 扫描 到n的height  ,如果有

【hihocoder#1413】Rikka with String 后缀自动机 + 差分

题目链接:http://hihocoder.com/problemset/problem/1413 这个题非常的劲! 首先可以发现,每次只变换一个字符为#,所以每次答案一定会得到相应的包含#的答案,而这个方案是可以直接计算出来的. 假设是$S[i]=$#则会得到$i*(N-i+1)$的子串数. 所以每次的答案可以表示为$sum[root]+i*(N-i+1)-ans[i]$,其中$ans[i]$表示严格经过$i$位置的本质不同的子串,严格的意义即这个本质不同的子串有且仅有一次,且经过$i$: 所

HDU 5030 Rabbit&#39;s String

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5030 题意:给出一个长度为n的串S,将S分成最多K个子串S1,S2,……Sk(k<=K).选出每个子串Si(1<=i<=k)的最大子串SSi.最后使得k个SSi的最大值最小. 思路:首先用后缀数组求出所有子串.二分答案串,判定是否存在一种分法满足要求.对于答案串A,设A起始位置所组成的后缀排名为t,在排名为[t+1,n]的后缀中截取子串S[Li,Ri],使得Ri<n(下标1到n),且该

hdu 4850 Wow! Such String!(字符串处理,yy)

题目 参考了博客http://blog.csdn.net/u013368721/article/details/37575165 //用visit[26][26][26][26]来判断新家新区的子母河前三个组合而成的4个字符的串是否和之前的重复. //再加上最初三个字符,所以,总共有26*26*26*26+3的长度. /* //以下复制自博客http://blog.csdn.net/u013368721/article/details/37575165 题目大意:给你一个整数n,让你输出一个字符