【Poj-3693】Maximum repetition substring 后缀数组 连续重复子串

时间:2020-05-13
本文章向大家介绍【Poj-3693】Maximum repetition substring 后缀数组 连续重复子串,主要包括【Poj-3693】Maximum repetition substring 后缀数组 连续重复子串使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

POJ - 3693

题意

SPOJ - REPEATS 的进阶版,在这题的基础上输出字典序最小的重复字串。

思路

跟上题一样,先求出最长的重复次数,在求的过程中顺便纪录最多次数可能的长度。

因为sa数组是按照字典序排好的,所以我们顺序遍历sa数组,找到第一个符合的输出即可。

PS:

通过这题大致知道了为什么之前看到有的后缀数组代码需要在字符串最后加一个0。

(我的模板是OI-wiki上的,没有这一步,而且之前也没错过,可能是之前做过的题目数据没有卡到,这题只有a和b,就很大可能会出问题)。

写完之后一直有问题,还找不到bug,在网上看到一个代码,把相应的数组清零了,我就清零了rank数组,就过了,然后试了一下只把rank[n+1]变为0,也过了。

我就找了一下哪里会出这个问题,猜可能是因为求height数组的时候,没有判断越界,所以height数组就可能出错。类似下面

char str[100];
while(~scanf("%s",str))
{
    for(int i=0;i<10;i++) printf("%c",str[i]);
    printf("\n");
}
/*
input:
1111111111
0000
output:
1111111111
0000 11111
*/

加上越界判断之后,不用清空rank,就过掉了。

所以加0,可能就是为了书写方便。。。。

代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<math.h>
#define pb push_back
typedef long long ll;
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 1e5+10;

int sa[N],cnt[N],pos[N],rk[N],oldrk[N],ht[N],n,m;
char str[N];
bool cmp(int a,int b,int k)
{
    return oldrk[a]==oldrk[b]&&oldrk[a+k]==oldrk[b+k];
}
void getsa()
{
    memset(cnt,0,sizeof(cnt));
    m=122;
    for(int i=1; i<=n; ++i) ++cnt[rk[i]=str[i]];
    rk[n+1]='c';//加之前没有出现过的也可以
    for(int i=1; i<=m; ++i) cnt[i]+=cnt[i-1];
    for(int i=n; i; i--) sa[cnt[rk[i]]--]=i;
    for(int k=1; k<=n; k<<=1)
    {
        int num=0;
        for(int i=n-k+1; i<=n; ++i) pos[++num]=i;
        for(int i=1; i<=n; ++i) if(sa[i]>k) pos[++num]=sa[i]-k;
        memset(cnt,0,sizeof(cnt));
        for(int i=1; i<=n; ++i) ++cnt[rk[i]];
        for(int i=1; i<=m; ++i) cnt[i]+=cnt[i-1];
        for(int i=n; i; i--) sa[cnt[rk[pos[i]]]--]=pos[i];
        num=0;
        memcpy(oldrk,rk,sizeof(rk));
        for(int i=1; i<=n; ++i) rk[sa[i]]=cmp(sa[i],sa[i-1],k)?num:++num;
        if(num==n) break;
        m=num;
    }
    for(int i=1; i<=n; ++i)
        rk[sa[i]]=i;
    int k=0;
    for(int i=1; i<=n; ++i)
    {
        if(k) --k;
        while(str[i+k]==str[sa[rk[i]-1]+k]) ++k;
        //下面就是加上越界判断
//        while(i+k<=n&&sa[rk[i]-1]+k<=n&&str[i+k]==str[sa[rk[i]-1]+k])
//            ++k;
        ht[rk[i]]=k;
    }
}
int dp[N][20];
void RMQ()
{
    for(int i=1; i<=n; ++i) dp[i][0]=ht[i];
    for(int j=1; (1<<j)<=n; ++j)
    {
        for(int i=1; i+(1<<j)-1<=n; ++i)
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    }
}
int query(int l,int r)
{
    int k=0;
    while((1<<(k+1))<=(r-l+1)) ++k;
    //int k=int(log(r-l+1.0)/log(2.0));// 比上面慢
    return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
int lcp(int i,int j)
{
    i=rk[i],j=rk[j];
    if(i>j) swap(i,j);
    return query(i+1,j);
}
int tot,len[N];
int main()
{
    int cas=0;
    while(~scanf("%s",str+1)&&strcmp(str+1,"#"))
    {
        tot=0;
        n=strlen(str+1);
        getsa();
        RMQ();
        printf("Case %d: ",++cas);
        int ans=0;
        for(int i=1; i<=n; ++i)
        {
            for(int j=1; j+i<=n; j+=i)
            {
                int now=lcp(j,j+i);
                int num=now/i+1;
                int k=j-(i-now%i);
                if(k>0&&lcp(k,k+i)>=i) ++num;
                if(num>ans)
                {
                    ans=num;
                    tot=0;
                    len[tot++]=i;
                }
                else if(num==ans)
                {
                    if(len[tot-1]!=i)
                        len[tot++]=i;
                }
            }
        }
        int flag=0;
        for(int i=1; i<=n; ++i)
        {
            for(int j=0; j<tot; ++j)
            {
                int l=len[j];
                if(lcp(sa[i],sa[i]+l)>=(ans-1)*l)
                {
                    str[sa[i]+ans*l]='\0';//使用结束符比一个个输出快
                    printf("%s\n",str+sa[i]);
                    flag=1;
                    break;
                }
            }
            if(flag)
                break;
        }
    }
    return 0;
}
/*
*/

原文地址:https://www.cnblogs.com/valk3/p/12883509.html