后缀数组题目

巨佬博客: https://www.cnblogs.com/zwfymqz/p/8413523.html

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1e6+10;
int n,M,sa[N],rk[N],tp[N],sum[N],hight[N];
char s[N];

void Qsort() {
    for(int i=0;i<=M;i++) sum[i]=0;
    for(int i=1;i<=n;i++) sum[rk[i]]++;
    for(int i=1;i<=M;i++) sum[i]+=sum[i-1];
    for(int i=n;i>=1;i--) sa[ sum[rk[tp[i]]]-- ]=tp[i];
}

void suffixsort() {
    M=100;
    for(int i=1;i<=n;i++) rk[i]=s[i]-‘0‘+1,tp[i]=i;
    Qsort();
    for(int w=1,p=0;p<n;M=p,w<<=1) {
        p=0;
        for(int i=1;i<=w;i++)tp[++p]=n-w+i;
        for(int i=1;i<=n;i++) if(sa[i]>w)tp[++p]=sa[i]-w;
        Qsort();
        swap(tp,rk);
        rk[sa[1]]=p=1;
        for(int i=2;i<=n;i++)
            rk[sa[i]]=( tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w] )?p:++p;
    }
}

void gethight() {
    int j,k=0;
    for(int i=1;i<=n;i++) {
        if(k)k--;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])k++;
        hight[rk[i]]=k;
    }
}

int main() {
    scanf("%s",s+1);n=strlen(s+1);
    suffixsort();
    for(int i=1;i<=n;i++) printf("%d ",sa[i]);
}

后缀数组模板

$sa[i]:排名为i的后缀的位置$

$rk[i]:从第i个位置开始的后缀的排名,下文为了叙述方便,把从第i个位置开始的后缀简称为后缀i$

$tp[i]:基数排序的第二关键字,意义与sa一样,即第二关键字排名为i的后缀的位置$

$sum[i]:ii号元素出现了多少次。辅助基数排序$

$s:字符串,s[i]表示字符串中第i个字符串$

$height[i]:lcp(sa[i],sa[i−1]),即排名为i的后缀与排名为i−1的后缀的最长公共前缀$

Long Long Message POJ - 2774

题意:

$一个人读取同一个字符串两次,因为机器的问题,每次读取可能会在原串的左边和右边加上一串随机字符串, 问原串的最大长度$

题解:

  • $将两个串合并成一个串$
  • $求出height,     所以只要遍历所有的height 求出最大值即可  注意判定height所表示的第i串和第i-1串是否在两个串里$

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
typedef long long ll;

const int N=2e5+10;
int n,M,sa[N],rk[N],tp[N],sum[N],height[N],lens,lens1;
char s[N],s1[N];

void Qsort() {
    for(int i=0;i<=M;i++) sum[i]=0;
    for(int i=1;i<=n;i++) sum[rk[i]]++;
    for(int i=1;i<=M;i++) sum[i]+=sum[i-1];
    for(int i=n;i>=1;i--) sa[ sum[rk[tp[i]]]-- ]=tp[i];
}

void suffixsort() {
    M=100;
    for(int i=1;i<=n;i++) rk[i]=s[i]-‘0‘+1,tp[i]=i;
    Qsort();
    for(int w=1,p=0;p<n;M=p,w<<=1) {
        p=0;
        for(int i=1;i<=w;i++)tp[++p]=n-w+i;
        for(int i=1;i<=n;i++) if(sa[i]>w)tp[++p]=sa[i]-w;
        Qsort();
        swap(tp,rk);
        rk[sa[1]]=p=1;
        for(int i=2;i<=n;i++)
            rk[sa[i]]=( tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w] )?p:++p;
    }
}

void getheight() {
    int j,k=0;
    for(int i=1;i<=n;i++) {
        if(k)k--;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])k++;
        height[rk[i]]=k;
    }
}

bool ok(int x,int y) {
    if(x>y)swap(x,y);
    return x>=1&&x<=lens&&y>=lens+1&&y<=lens+lens1;
}

int main() {
    scanf("%s",s+1); lens=strlen(s+1);
    scanf("%s",s1+1); lens1=strlen(s1+1);
    strcat(s+1,s1+1);
    n=lens+lens1;
    suffixsort();getheight();int ans=0;

    for(int i=2;i<=lens+lens1;i++)
        if(ok(sa[i],sa[i-1]))ans=max(ans,height[i]);
    cout<<ans;
}

牛奶模式Milk Patterns P2852

题意:

$求出给定串的重复 k 次的重复子串,使之长度最大化 $

题解:

  • 和上面那题非常类似  只要选k个后缀 求其最大公共前缀长度 ,并使之最大化即可
  • 用单调栈跑height数组即可 单调栈维护长度为k-1的最小值
  • 注意最好离散化 不然基数排序容易T
  • 求相同子串肯定是和height有关

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=2e5+10;
int n,M,sa[N],rk[N],tp[N],sum[N],height[N],lens,lens1;
int s[N],b[N],st[N],k,ans=0;

void Qsort() {
    for(int i=0;i<=M;i++) sum[i]=0;
    for(int i=1;i<=n;i++) sum[rk[i]]++;
    for(int i=1;i<=M;i++) sum[i]+=sum[i-1];
    for(int i=n;i>=1;i--) sa[ sum[rk[tp[i]]]-- ]=tp[i];
}

void suffixsort() {
    for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
    Qsort();
    for(int w=1,p=0;p<n;M=p,w<<=1) {
        p=0;
        for(int i=1;i<=w;i++)tp[++p]=n-w+i;
        for(int i=1;i<=n;i++) if(sa[i]>w)tp[++p]=sa[i]-w;
        Qsort();
        swap(tp,rk);
        rk[sa[1]]=p=1;
        for(int i=2;i<=n;i++)
            rk[sa[i]]=( tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w] )?p:++p;
    }
}

void getheight() {
    int j,k=0;
    for(int i=1;i<=n;i++) {
        if(k)k--;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])k++;
        height[rk[i]]=k;
    }
}

int main() {
    cin>>n>>k;k--;
    for(int i=1;i<=n;i++)scanf("%d",&s[i]),b[i]=s[i];
    sort(b+1,b+1+n);
    int nn=unique(b+1,b+1+n)-b-1;M=nn;
    for(int i=1;i<=n;i++)s[i]=lower_bound(b+1,b+1+nn,s[i])-b;
    suffixsort();getheight();
    int l=1,r=0;
    for(int i=2;i<=n;i++) {
        if(l<=r&&st[l]<i-k+1)l++;
        while(l<=r&&height[st[r]]>height[i])r--;
        st[++r]=i;
        ans=max(ans,height[st[l]]);
    }
    cout<<ans;
}

原文地址:https://www.cnblogs.com/bxd123/p/11793833.html

时间: 2024-10-12 09:16:28

后缀数组题目的相关文章

后缀数组题目整理

最近在跟着 罗穗骞 的论文学习后缀数组, 不亏是神牛的论文.无论是算法讲解,还是习题举例都非常不错.下面把最进做的几道后缀数组整理一下. 1.两字符串的最长公共子串 1 #include <stdio.h> 2 #include <iostream> 3 #include <algorithm> 4 #include <sstream> 5 #include <stdlib.h> 6 #include <string.h> 7 #in

CSU1656: Paper of FlyBrother(后缀数组)

Description FlyBrother is a superman, therefore he is always busy saving the world. To graduate from NUDT is boring but necessary for him. Typically We need to post an paper to get Graduate Certificate, however being one superman, FlyBrother wants to

hdu4416 Good Article Good sentence (后缀数组)

题意:问a串中有多少种字符串集合B中没有的连续子串. a的长度10^5,B中的总长度为不超过10^5. 解法:后缀数组题目:后缀数组能够非常easy算出来一个串中有多少种子串. 把a和B集合连起来.求一次不同子串数量,然后减掉B相互连起来的数量. 在求时候,要减掉含有链接符的子串,方法是扫一遍,枚举最后出现的连接符. 代码: /****************************************************** * @author:xiefubao ***********

后缀数组 &amp; 题目

后缀数组被称为字符串处理神器,要解决字符串问题,一定要掌握它.(我这里的下标全部都是从1开始) 首先后缀数组要处理出两个数组,一个是sa[],sa[i]表示排名第i为的后缀的起始位置是什么,rank[i]表示第i个字符为起始点的后缀,它的排名是什么.可以知道sa[rank[i]] = i; rank[sa[i]] = i; 由于每个后缀各不相同,至起码长度不同,所以每个后缀是不可能相等的. 解除一个值,就能在O(n)时间内得到另外一个. 定义:suffix(i)表示从[i, lenstr]这个后

HDOJ 题目4416 Good Article Good sentence(后缀数组求a串子串在b串中不出现的种类数)

-每周六晚的BestCoder(有米!) Good Article Good sentence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2784    Accepted Submission(s): 785 Problem Description In middle school, teachers used to encour

POJ 题目1743 Musical Theme(后缀数组,求一个串中最长不重叠重复子串)

Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21826   Accepted: 7467 Description A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the

UVA 题目1223 - Editor(后缀数组求出现次数超过两次的最长子串的长度)

Mr. Kim is a professional programmer. Recently he wants to design a new editor which has as many functions as possible. Most editors support a simple search function that finds one occurrence (or all occurrences successively) of a query pattern strin

POJ 题目3581 Sequence(后缀数组)

Sequence Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5738   Accepted: 1227 Case Time Limit: 2000MS Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An,  you are to cut it into three sub-sequences and

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6