SPOJ- Distinct Substrings(后缀数组&后缀自动机)-程序员宅基地

技术标签: 数据结构与算法  

Given a string, we need to find the total number of its distinct substrings.

Input

T- number of test cases. T<=20;
Each test case consists of one string, whose length is <= 1000

Output

For each test case output one number saying the number of distinct substrings.

Example

Sample Input:
2
CCCCC
ABABA

Sample Output:
5
9

Explanation for the testcase with string ABABA: 
len=1 : A,B
len=2 : AB,BA
len=3 : ABA,BAB
len=4 : ABAB,BABA
len=5 : ABABA
Thus, total number of distinct substrings is 9.

题解:

本题题意就是给你一个字符串,让你找它有多少不同的子串;

其实就是SAM的板题,只要求每一个状态点的longest[i]-longest[fa[i]]的和就行了。

但由于是后缀数组专题,还是用后缀数组写:

 

参考代码:

  后缀自动机:

#include<bits/stdc++.h>
using namespace std;
#define PI acos(-1.0)
#define mkp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
char s[maxn];
struct SAM{
    ll ans;
    int fa[maxn<<1],l[maxn<<1],nxt[maxn<<1][26],last,cnt;
    void Init()
    {
        memset(nxt[1],0,sizeof(nxt[1]));
        last=cnt=1; ans=0;
        fa[1]=0;l[1]=0;
    }
    
    int NewNode()
    {
        ++cnt;
        memset(nxt[cnt],0,sizeof(nxt[cnt]));
        fa[cnt]=l[cnt]=0;
        return cnt;
    }
    
    void Add(int c)
    {
        int p=last,np=NewNode();
        last=np;l[np]=l[p]+1;
        while(p&&!nxt[p][c]) nxt[p][c]=np,p=fa[p];
        if(!p) fa[np]=1;
        else
        {
            int q=nxt[p][c];
            if(l[q]==l[p]+1) fa[np]=q;
            else
            {
                int nq=NewNode();
                memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
                fa[nq]=fa[q];
                l[nq]=l[p]+1;
                fa[q]=fa[np]=nq;
                while(nxt[p][c]==q) nxt[p][c]=nq,p=fa[p]; 
            }
        }
        ans+=(l[last]-l[fa[last]])*1ll;    
    }
    
    void Query()
    {
        Init();
        for(int i=0,len=strlen(s);i<len;++i) Add(s[i]-'A');
        printf("%lld\n",ans);
    }
} sam;

int main()
{
    int N;
    scanf("%d",&N);
    while(N--)
    {
        sam.Init();
        scanf("%s",s);
        sam.Query();
    }
    return 0;
}
View Code

  后缀数组:

#include<iostream>
#include<cstdio>
#include<cstring>
#define rint register int
#define ini inline int
#define maxn 1000050
using namespace std;
char str[maxn];
int y[maxn<<1],x[maxn<<1],c[maxn];
int sa[maxn],rk[maxn],height[maxn];
int n,m,s[maxn];

inline void get_SA() 
{
    for(int i=1;i<=m;++i) c[i]=0;
    for(int i=1;i<=n;++i) ++c[x[i]=s[i]];
    for(int i=2;i<=m;++i) c[i]+=c[i-1];
    for(int i=n;i>=1;--i) sa[c[x[i]]--]=i;
    for(int k=1;k<=n;k<<=1) 
    {
        int num=0;
        for(int i=n-k+1;i<=n;++i) y[++num]=i;
        for(int i=1;i<=n;++i) if(sa[i]>k) y[++num]=sa[i]-k;
        for(int i=1;i<=m;++i) c[i]=0;
        for(int i=1;i<=n;++i) ++c[x[i]];
        for(int i=2;i<=m;++i) c[i]+=c[i-1]; 
        for(int i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
        swap(x,y);
        x[sa[1]]=1;
        num=1;
        for(rint i=2;i<=n;++i)
            x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
        if(num==n) break;
        m=num;
    }
}
inline void get_height() 
{
    int k=0;
    for(int i=1;i<=n;++i) rk[sa[i]]=i;
    for(int i=1;i<=n;++i) 
    {
        if(rk[i]==1) continue;//第一名height为0
        if(k) --k;//h[i]>=h[i-1]-1;
        rint j=sa[rk[i]-1];
        while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k]) ++k;
        height[rk[i]]=k;//h[i]=height[rk[i]];
    }
}
int main() 
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",str+1);
        n=strlen(str+1);m=256;
        for(int i=1;i<=n;++i) s[i]=str[i]-'A'+1;
        get_SA();
        get_height();
        //for(int i=1;i<=n;++i) cout<<sa[i]<<" "<<height[i]<<endl;
        int ans=0;
        for(int i=1;i<=n;++i) ans+=n-sa[i]+1-height[i];
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/songorz/p/11205770.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30344995/article/details/99216735

智能推荐

深度学习杰出人物专访系列(Andrew Ng)分享(一)_深度学习英雄”(heroes of deep learning)-程序员宅基地

文章浏览阅读2.7k次。两天前,Yotube用户Preserve Knowledge,在Youtube上分享了一套Andrew NG采访深度学习领域的杰出人物以一套视频,包括深度学习之父Geffery Hinton,卷积神经网络创始人Yoshua Bengio,生成对抗GAN创始人Ian Goodfellow等等,分享大牛们的深度学习之路,非常不错的经验,我也将陆续和大将分享这些视频,今天与大家分享NG采访Geffery_深度学习英雄”(heroes of deep learning)

python科学计算常用包-python常用包及功能介绍-程序员宅基地

文章浏览阅读2.2k次。1.NumPy数值计算NumPy是使用Python进行科学计算的基础包,Numpy可以提供数组支持以及相应的高效处理函数,是Python数据分析的基础,也是SciPy、Pandas等数据处理和科学计算库最基本的函数功能库,且其数据类型对Python数据分析十分有用。它包含:一个强大的N维数组对象复杂的(广播)功能用于集成C / C ++和Fortran代码的工具有用的线性代数,傅里叶变换和随机数功..._python科学计算要安装的包

Vue + ElementUI 项目中使用vue-pdf 实现简单预览_vue+elementui使用vue-pdf实现预览功能-程序员宅基地

文章浏览阅读6k次。Vue + ElementUI 项目中使用vue-pdf 实现简单预览1、安装 vue-pdfnpm install --save vue-pdf2、在vue页面中导入对应的组件我这是通过点击 预览 按钮 获取id打开一个dialog来实现<!--PDF 预览--> <el-dialog :title="PDF 预览" ..._vue+elementui使用vue-pdf实现预览功能

C语言指针及占据内存空间_c语言 指针占用空间-程序员宅基地

文章浏览阅读1.7k次,点赞12次,收藏30次。目录:第一、了解内存空间第二、理解指针第三、指针运算问题正文:第一、了解内存空间本文章文字有点多,会有点枯燥,配合图文一起看可以缓解枯燥,耐心阅读哦!!!先了解内存地址,才更好的理解指针!我们可以把内存想象为成一列很长很长的货运火车,有很多大小相同的车厢,而每个车厢正好相当于在内存中表示一个字节。这些车厢装着不同的货物,就像我们的内存要存着各式..._c语言 指针占用空间

C++ 实时显示7z压缩与解压缩的进度_c++实时获取解压进度-程序员宅基地

文章浏览阅读3.5k次。一、7zip下载地址:https://www.7-zip.org/sdk.html二、nmake编译下载完后,进入文件夹:使用VS的命令行工具(nmake)进行编译(命令:nmake /f makefile),在当前目录下生成x86文件夹,里面有本次编译的成果文件:7zra.dll三、转换示例工程(dsw转vs08)打开client7z工程,下载下来的是由dsw格式(N年前的格式,真是不懂得与时俱进),将其用vs08打开(vs17版本打开,会转换失败)四、修改示例代码打开client_c++实时获取解压进度

2021CCPC广州 H. Three Integers-程序员宅基地

文章浏览阅读2k次。题目链接You are given three non-negative integers aaa, bbb, and ccc. Find three positive integers xxx, yyy, and zzz that satisfy x mod y=ax\bmod y=axmody=a, y mod z=by\bmod z=bymodz=b, and z mod x=cz\bmod x=czmodx=c.InputThe first line contains an integer t_h. three integers

随便推点

vue图片视频预览_vue 页面预览视频-程序员宅基地

文章浏览阅读552次。vue图片预览_vue 页面预览视频

学习好并用好大模型-程序员宅基地

文章浏览阅读842次,点赞20次,收藏12次。大模型是个好东西,学好并用好益处多多~

[UEFI开发] Linux Ubuntu EDK2环境搭建_ubuntu edk2 uefi-程序员宅基地

文章浏览阅读2.9k次,点赞4次,收藏18次。[UEFI开发]配置EDK2开发环境 (Ubuntu X86_64)_ubuntu edk2 uefi

HTML基础(一)-程序员宅基地

文章浏览阅读977次。更新中~~文章目录常用浏览器以及内核常用浏览器以及内核

JS:Uint8Array 数组类型、arraybuffer对象类型与十六进制字符串互转-程序员宅基地

文章浏览阅读2.3w次,点赞7次,收藏36次。最近,在做区块链浏览器,调用合约与链上进行数据通信的时候,需要将对象转化成十六进制字符串,看看下 javascript 关于 ArrayBuffer 类型的api文档,新的如下:arraybuffer类型转16进制字符串function buf2hex(buffer) { return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).j._uint8array

write.wait_for_active_shards参数和 refresh参数实现elasticsearch同步写入_wait_for_active_shards=0-程序员宅基地

文章浏览阅读2.9w次,点赞3次,收藏3次。  elasticsearch一般称为近实时的大数据处理引擎,为什么是近实时呢?原因是当我们提交索引数据时,实际上只是写到了Buffer里面,并不是立即可搜索的,最多需要等1秒才可搜索(index.refresh_interval由这个参数控制,可以通过动态API自定义设置,或在建索引时在settings里面设置),还有一点,当存在副本时,只保证主分片写入成功写入请求就会返回,此时搜索请求如果分配..._wait_for_active_shards=0

推荐文章

热门文章

相关标签