码迷,mamicode.com
首页 > 编程语言 > 详细

后缀数组题目

时间:2019-11-04 19:38:05      阅读:85      评论:0      收藏:0      [点我收藏+]

标签:nbsp   turn   for   har   ddd   cin   tom   读取   class   

巨佬博客: 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;
}
View Code

 

 

牛奶模式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;
}
View Code

 

 

 

 

 

后缀数组题目

标签:nbsp   turn   for   har   ddd   cin   tom   读取   class   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!