poj 3693 求出现次数最多的连续重复子串(具体的串)黑盒

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;

const int N=2*100100;
int cl,rk[N],sa[N],Rs[N],y[N],wr[N],h[N],r[N][30];
char c[N];

int minn(int x,int y){return x<y ? x:y;}

void get_sa(int m)
{
    for(int i=1;i<=cl;i++) rk[i]=c[i]-'a'+1;
    for(int i=1;i<=m;i++) Rs[i]=0;
    for(int i=1;i<=cl;i++) Rs[rk[i]]++;
    for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
    for(int i=cl;i>=1;i--) sa[Rs[rk[i]]--]=i;

    int ln=1,p=0;
    while(p<cl)
    {
        int k=0;
        for(int i=cl-ln+1;i<=cl;i++) y[++k]=i;
        for(int i=1;i<=cl;i++) if(sa[i]>ln) y[++k]=sa[i]-ln;

        for(int i=1;i<=cl;i++) wr[i]=rk[y[i]];
        for(int i=1;i<=m;i++) Rs[i]=0;
        for(int i=1;i<=cl;i++) Rs[wr[i]]++;
        for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
        for(int i=cl;i>=1;i--) sa[Rs[wr[i]]--]=y[i];

        for(int i=1;i<=cl;i++) wr[i]=rk[i];
        for(int i=cl+1;i<=cl+ln;i++) wr[i]=0;
        p=1;rk[sa[1]]=1;
        for(int i=2;i<=cl;i++)
        {
            if(wr[sa[i]]!=wr[sa[i-1]] || wr[sa[i]+ln]!=wr[sa[i-1]+ln]) p++;
            rk[sa[i]]=p;
        }
        ln*=2,m=p;
    }
    sa[0]=0,rk[0]=0;
}

void get_h()
{
    int k=0,j;
    for(int i=1;i<=cl;i++) if(rk[i]!=1)
    {
        j=sa[rk[i]-1];
        if(k) k--;
        while(c[j+k]==c[i+k] && j+k<=cl && i+k<=cl) k++;
        h[rk[i]]=k;
    }
    h[1]=0;
}

void get_rmq()
{
    for(int i=1;i<=cl;i++) r[i][0]=h[i];
    for(int j=1;(1<<j)<=cl;j++)
        for(int i=1;i+(1<<j)-1<=cl;i++)
        {
            r[i][j]=minn(r[i][j-1],r[i+(1<<(j-1))][j-1]);
        }
}

int query_rmq(int i,int j)
{
    if(i>j) swap(i,j);
    i++;
    int k=0;
    while(i+(1<<(k+1)) <= j) k++;
    return minn(r[i][k],r[j-(1<<k)+1][k]);
}

int main()
{
    int x,y,z,t0,t1,now,ans,al,ar,T=0;
    while(1)
    {
        scanf("%s",c+1);
        cl=strlen(c+1);
        if(cl==1 && c[1]=='#') return 0;
        printf("Case %d: ",++T);
        get_sa(30);
        get_h();
        get_rmq();
        ans=0;al=ar=0;
        for(int L=1;L*2<=cl;L++)
        {
            for(int i=0;L*(i+1)+1<=cl;i++)
            {
                x=L*i+1,y=L*(i+1)+1;
                if(c[x]!=c[y]) continue;    
                z=query_rmq(rk[x],rk[y]);
                t1=y+z-1;
                t0=0;
                for(int j=0;j<=L-1;j++)//往前匹配
                {
                    if(x-j<1 || c[x-j]!=c[y-j]) break;
                    t0=x-j;
                    now=((t1-t0+1)/L);
                    if(now>ans || (now==ans && rk[t0]<rk[al])) ans=now,al=t0,ar=t0+now*L-1;
                }
            }
        }
        if(ans==0) printf("%c\n",c[sa[1]]);
        else 
        {
            for(int i=al;i<=ar;i++) printf("%c",c[i]);printf("\n");
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值