POJ3693 Maximum repetition substring

题目

The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1.

Given a string containing lowercase letters, you are to find a substring of it with maximum repetition number.

大意是,给你一个字符串,让你输出其中重复次数最多的重复连续字串,如果次数相同就输出字典序最小的。

思路

一开始不好想。

首先,枚举串的长度\(L\),然后枚举区间\([1,L]\)\([L+1,2*L]\),会发现,一个连续重复子串总会被截头去尾的被枚举到。

比如cabababc,在枚举到长度\(L=2\)的时候,中间的那段baba就会被枚举到,然而实际上可能是去了头尾的,注意到LCP求出后后面会多出一段,定义\(R=LCP\),那么,R%L就是多出来的一段,可以看成是前面少取了L-R%L这一段,然后判断是不是可以把这一段补上,就完成了第一步:找到一段区间内的最长重复连续子串。

然后考虑第二步:要求字典序最小。

我们把这些可能成为答案的串先存起来,然后按照的顺序一遍扫描,因为sa天然有序,所以就可以得到最终的答案了。

代码
#include<cstdio>
#include<string.h>
#include<algorithm> 
#include<iostream>
#define M 100005
using namespace std;
int sa[M],rk[M],t1[M],t2[M],tmp[M],cnt1[M],cnt2[M],H[M];
struct node{
    int x,id;
    bool operator < (const node&  res)const{
        if(x!=res.x)return x<res.x;
        return id<res.id;
    }
}A[M];
void Init(char *s,int n){
    for(int i=1;i<=n;i++)A[i]=(node){s[i],i};
    sort(A+1,A+n+1);
    for(int i=1;i<=n;i++)sa[i]=A[i].id; 
    rk[sa[1]]=1;
    for(int i=2;i<=n;i++){
        rk[sa[i]]=rk[sa[i-1]];
        if(s[sa[i]]!=s[sa[i-1]])rk[sa[i]]++; 
    }
    for(int l=1;rk[sa[n]]<n;l<<=1){
        for(int i=0;i<=n;i++)cnt1[i]=cnt2[i]=0;
        for(int i=1;i<=n;i++)cnt1[t1[i]=rk[i]]++,cnt2[t2[i]=(l+i<=n)?rk[i+l]:0]++;
        for(int i=1;i<=n;i++)cnt1[i]+=cnt1[i-1],cnt2[i]+=cnt2[i-1];
        for(int i=n;i>=1;i--)tmp[cnt2[t2[i]]--]=i;
        for(int i=n;i>=1;i--)sa[cnt1[t1[tmp[i]]]--]=tmp[i];
        rk[sa[1]]=1;
        for(int i=2;i<=n;i++){
            rk[sa[i]]=rk[sa[i-1]];
            if(t1[sa[i]]!=t1[sa[i-1]]||t2[sa[i]]!=t2[sa[i-1]])rk[sa[i]]++;
        }
    }
    for(int i=1,j=0;i<=n;i++){
        j-=j>0;
        while(s[i+j]==s[sa[rk[i]-1]+j])j++;
        H[rk[i]]=j;
    }
}
struct Stable{
    int mn[M][21],Log[M];
    void Init(int n){
        for(int i=1;i<=n;i++){
            mn[i][0]=H[i];
            if(i>1)Log[i]=Log[i>>1]+1;
        }
        for(int j=1;j<21;j++)
            for(int i=1;i+(1<<j-1)<=n;i++)
                mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]);
    }
    int Query(int l,int r){
        int t=Log[r-l+1];
        return min(mn[l][t],mn[r-(1<<t)+1][t]);
    }
}st;
int LCP(int l,int r){
    l=rk[l],r=rk[r];
    if(l>r)swap(l,r);
    return st.Query(l+1,r);
}
char S[M];
int n,cas=0,a[M],cnt;
int main(){
    while(scanf("%s",S+1)&&S[1]!='#'){
        n=strlen(S+1);
        Init(S,n);
        st.Init(n);
        int ans=0;
        for(int L=1;L<=n;L++){
            for(int i=1;i<=n;i+=L){
                int R=LCP(i,i+L),step=R/L+1,k=i-(L-R%L);
                if(k>=0&&R%L)if(LCP(k,k+L)>=R)step++;
                if(step>ans){ans=step;cnt=0;a[cnt++]=L;}
                else if(step==ans)a[cnt++]=L;
            }
        }
        int len=-1,st;
        for(int i=1;i<=n&&len==-1;i++){
            for(int j=0;j<cnt;j++){
                int L=a[j];
                if(LCP(sa[i],sa[i]+L)>=(ans-1)*L){
                    len=L;st=sa[i];break;
                }
            }
        }       
        printf("Case %d: ",++cas);
        for(int i=st;i<st+len*ans;i++)printf("%c",S[i]);
        putchar('\n');
        for(int i=1;i<=n;i++)S[i]=0;
    }
    return 0;
}

转载于:https://www.cnblogs.com/zryabc/p/11202144.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值