HihoCoder - 1445 后缀自动机 试水题

题意:求子串个数

SAM中每个子串包含于某一个状态中

对于不同的状态\(u,v\),\(sub(u)∩sub(v)=NULL\)

因此答案就是对于所有的状态\(st\),\(ans=\sum_{st} maxlen(st)-minlen(st)+1\)

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rrep(i,j,k) for(int i=j;i>=k;i--)
#define println(a) printf("%lld\n",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
typedef long long ll;
using namespace std;
const int MAXN = 2e6+11;
const ll oo = 0x3f3f3f3f3f3f3f3f;
const ll ooo= 0x3f3f3f3f;
ll read(){
    ll x=0,f=1;register char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
struct SAM{
    int tot;
    char str[MAXN];
    int maxlen[MAXN],minlen[MAXN],trans[MAXN][26],slink[MAXN];
    void init(){
        tot=1;
        maxlen[tot]=minlen[tot]=slink[tot]=0;
        rep(i,0,25) trans[tot][i]=0;
    }
    int node(int mx,int mn,int from,int _slink){
        ++tot;
        maxlen[tot]=mx;
        minlen[tot]=mn;
        slink[tot]=_slink;
        rep(i,0,25) trans[tot][i]=trans[from][i];
        return tot;
    }
    int add(char ch,int u){
        int c=ch-‘a‘,v=u;
        int z=node(maxlen[u]+1,-1,0,0);
        while(v&&trans[v][c]==0){
            trans[v][c]=z;
            v=slink[v];
        }
        if(v==0){
            minlen[z]=1;
            slink[z]=1;
            return z;
        }
        int x=trans[v][c];
        if(maxlen[v]+1==maxlen[x]){
            minlen[z]=maxlen[x]+1;
            slink[z]=x;
            return z;
        }
        int y=node(maxlen[v]+1,-1,x,slink[x]);
        slink[z]=slink[x]=y;
        minlen[x]=minlen[z]=maxlen[y]+1;
        while(v&&trans[v][c]==x){
            trans[v][c]=y;
            v=slink[v];
        }
        minlen[y]=maxlen[slink[y]]+1;
        return z;
    }
    void build(){
        int t=tot;
        int len=strlen(str+1);
        rep(i,1,len) t=add(str[i],t);
    }
}sam;
int main(){
    while(~scanf("%s",sam.str+1)){
        sam.init();
        sam.build();
        ll ans=0;
        rep(i,2,sam.tot) ans+=sam.maxlen[i]-sam.minlen[i]+1;
        println(ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/caturra/p/9556330.html

时间: 2024-09-29 21:30:48

HihoCoder - 1445 后缀自动机 试水题的相关文章

HIHOcoder 1445 后缀自动机二&#183;重复旋律5

思路 题目要求求出有多少个不同的子串出现 因为后缀自动机每个状态存储的是连续的后缀,所以一个状态对应的子串个数就是maxlen[x]-minlen[x]+1 代码 #include <cstdio> #include <algorithm> #include <cstring> #include <iostream> using namespace std; const int MAXN = 1000100*2; int maxlen[MAXN],minle

hihocoder #1465 : 后缀自动机五&#183;重复旋律8

#1465 : 后缀自动机五·重复旋律8 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 小Hi发现旋律可以循环,每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以对“循环相似旋律”进行相同的变换能继续得到原串的“循环相似旋律”. 小Hi对此产生了浓厚的兴趣,他有若干段旋律,和一部音乐作品.对于每一段旋律,他想知道有多少在音乐作品中的子串(重复便多

hihocoder #1457 : 后缀自动机四&#183;重复旋律7

#1457 : 后缀自动机四·重复旋律7 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的是小Hi发现了一部名字叫<十进制进行曲大全>的作品集,顾名思义,这部作品集里有许多作品,但是所有的作品有一个共同特征:只用了十个音符,所有的音符都表示成0-9的数字. 现在小Hi想知道这部作品中所有不同的旋律的“和”(也就是把串看成数字,在十进制下的求和,允许有前导0).答案有可能

hihocoder 1457 后缀自动机四&#183;重复旋律7 求不同子串的和

描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的是小Hi发现了一部名字叫<十进制进行曲大全>的作品集,顾名思义,这部作品集里有许多作品,但是所有的作品有一个共同特征:只用了十个音符,所有的音符都表示成0-9的数字. 现在小Hi想知道这部作品中所有不同的旋律的“和”(也就是把串看成数字,在十进制下的求和,允许有前导0).答案有可能很大,我们需要对(10^9 + 7)取摸. 解题方法提示 × 解题方法提示 小Hi:我们已经学习了后缀自动机,今天

hihocoder #1449 : 后缀自动机三&#183;重复旋律6

#1449 : 后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数.但是K不是固定的,小Hi想知道对于所有的K的答案. 解题方法提示 × 解题方法提示 小Hi:上次我们已经学习了后缀自动机了,今天我们再来解决一个用到后缀自动机的问题. 小Ho:好!那我们开始吧! 小Hi:现在我们要对K

POJ2774 后缀自动机&amp;后缀数组

http://poj.org/problem?id=2774 题目大意就是给两个字符串,求最长公共子串.好像可以哈希切掉,但是为了练一练后缀数组以及学一学后缀自动机,我用不同方法终于A掉了这道题. 后缀数组:就是求出height数组然后扫一遍,求出满足条件的最大值(满足条件是指height所指的两个后缀要没有公共部分),是后缀数组的水题 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 usin

hiho一下第128周 后缀自动机二&#183;重复旋律5

#1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中出现了多少不同的旋律? 解题方法提示 输入 共一行,包含一个由小写字母构成的字符串.字符串长度不超过 1000000. 输出 一行一个整数,表示答案. 样例输入 aab 样例输出 5 解题方法提示 小Hi:本周的题目其实就是给定一个字符串S,要求出S的所有不同子串的数

【BZOJ-3998】弦论 后缀自动机

3998: [TJOI2015]弦论 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2018  Solved: 662[Submit][Status][Discuss] Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个.T=1则表示不同位置的相同子串算作多个.K的意义如题所述. Output 输出仅

POJ 1509 Glass Beads 后缀自动机

题目大意:给出一个环形的字符串,问从哪里开始是的这个字符串的字典序最小. 思路:最小表示法和后缀自动机的裸题,不过我是为了学后缀自动机才写的这个题,就没有去学最小表示法. 做法很简单,先建立一个后缀自动机,然后从根开始沿tranc指针从a->z走len次到达的点就是字典序最小的字符串的结尾点,求起始点只要减一下长度再+1即可. 对于后缀自动机的理解:http://wyfcyx.is-programmer.com/posts/76107.html CODE: #include <cstdio&g