题目链接:点击查看

题目大意:给出一个字符串,求出字符串中 重复次数最多的连续重复子串 ,如果有多个答案,输出字典序最小的

题目分析:又是一个模板题,这里放一个大佬的博客,讲的很清楚:

https://blog.csdn.net/queuelovestack/article/details/53035903

具体做法就是,两层for循环,第一层枚举子串的长度,第二层枚举每个位置:0 , i , 2*i ... k*i,这样时间复杂度为nlogn,因为如果重复次数大于一次,那么必定会有相邻的两个位置 i*k 和 i*k+i 的最长公共前缀大于 i ,此时可以计算出重复次数ans为rmq(i*k,i*k+i)/i+1,这里的加一是因为本身的一次,在计算前缀时会覆盖掉,这里又出现了一个新的问题,如果子串的起点相对于之前枚举的位置在左右有所平移怎么办,因为向右计算的已经全部计算完毕了,我们只需要考虑向左是否还能扩大答案,因为在枚举的长度 i 固定的情况下,此时最多向左平移 i 个单位了,因为如果超过了 i 的话,那么就完全可以归为i*(k-1)与i*k的计算范围内了,所以为了凑整,我们令起点向左平移i-ans%i,此时的起点为i*k-(i-ans%i),我们记为st,再次计算看rmq(st,st+i)是否大于等于ans%i即可,为了方便起见,因为后面的字符串已经连接起来了,所以我们将判断条件更改为大于等于i就可以了,以此维护出现次数的最大值

以上为计算重复次数最多的连续重复子串的模板方法,下面说一下如何求字典序最小

此时我们已经获得了出现次数为mmax的所有长度的子字符串了,因为sa数组是通过排名排序的,我们枚举所有的sa数组,找到第一个满足rmq(sa[i],sa[i]+length[j])>=(mmax-1)*length的下标就是答案了,这里的mmax减一的原因和上面一样,也是因为在计算前缀的时候会少算字符串本身

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;char str[N];int sa[N]; //SA数组,表示将S的n个后缀从小到大排序后把排好序的
//的后缀的开头位置顺次放入SA中
int t1[N],t2[N],c[N];int rk[N],height[N],len;int s[N];int st[N][20];void build_sa(int s[],int n,int m)//n为添加0后的总长
{int i,j,p,*x=t1,*y=t2;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[i]=s[i]]++;for(i=1;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;for(j=1;j<=n;j<<=1) {p=0;for(i=n-j;i<n;i++) y[p++]=i;for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[y[i]]]++;for(i=1;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];swap(x,y);p=1,x[sa[0]]=0;for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;if(p>=n) break;m=p;}
}void get_height(int s[],int n)//n为添加0后的总长
{int i,j,k=0;for(i=0;i<=n;i++)rk[sa[i]]=i;for(i=0;i<n;i++) {if(k) k--;j=sa[rk[i]-1];while(s[i+k]==s[j+k]) k++;height[rk[i]]=k;}
}void solve(int base=128)
{build_sa(s,len+1,base);get_height(s,len);
}void ST_build()
{for(int i=1;i<=len;i++)st[i][0]=height[i];for(int i=1;i<=log2(len);i++)for(int j=1;j+(1<<i)-1<=len;j++)st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
}int ST_query(int a,int b)
{int l=rk[a],r=rk[b];if(l>r)swap(l,r);l++;int k=log2(r-l+1);return min(st[l][k],st[r-(1<<k)+1][k]);
}int main()
{
//  freopen("input.txt","r",stdin);
//  ios::sync_with_stdio(false);int kase=0;while(scanf("%s",str)!=EOF&&str[0]!='#'){len=strlen(str);for(int i=0;i<len;i++)s[i]=str[i]-'a'+1;s[len]=0;solve(30);ST_build();int mmax=0;vector<int>length;for(int i=1;i<=len;i++){for(int j=0;j+i<len;j+=i){int k=ST_query(j,j+i);int ans=k/i+1;int st=j-(i-k%i);if(ST_query(st,st+i)>=i)ans++;if(ans>mmax){mmax=ans;length.clear();length.push_back(i);}else if(ans==mmax){length.push_back(i);}}}for(int i=1;i<=len;i++)//枚举sa数组 {for(int j=0;j<length.size();j++){if(ST_query(sa[i],sa[i]+length[j])>=length[j]*(mmax-1)){printf("Case %d: ",++kase);for(int k=sa[i];k<sa[i]+length[j]*mmax;k++)putchar(str[k]);putchar('\n');goto end;}}}end:;}return 0;
}

POJ - 3693 Maximum repetition substring(后缀数组+RMQ)相关推荐

  1. POJ 3693 Maximum repetition substring (后缀数组)

    题目大意: 求出字典序最小,重复次数最多,的子串. 思路分析: RMQ + height 数组可以求出任意两个后缀的lcp 我们枚举答案字符串的重复的长度. 如果这个字符串的长度为 l ,而且这个字符 ...

  2. POJ-3693 Maximum repetition substring 后缀数组

    题目链接:http://poj.org/problem?id=3693 求字符串的重复次数最多的且字典序最小的字串. 很不错的题目.罗穗骞大牛论文的模板题,摘了Neo / Add ~0U>> ...

  3. 【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过

    题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&am ...

  4. 牛客-139 I. Substring(后缀数组 or 后缀自动机)

    牛客-139 I. Substring(后缀数组 or 后缀自动机) 题目链接 题意 一个由{a,b,c}\{a, b, c\}{a,b,c}组成的字符串SSS,求S子串的最大的集合,使得集合里的字符 ...

  5. hdu 2459 (后缀数组+RMQ)

    题意:让你求一个串中连续重复次数最多的串(不重叠),如果重复的次数一样多的话就输出字典序小的那一串. 分析:有一道比这个简单一些的题spoj 687, 假设一个长度为l的子串重复出现两次,那么它必然会 ...

  6. POJ3693 Maximum repetition substring

    题目 The repetition number of a string is defined as the maximum number R such that the string can be ...

  7. HDU - 4552 怪盗基德的挑战书(后缀数组+RMQ/KMP+dp)

    题目链接:点击查看 题目大意:给出一个字符串,统计每个前缀在字符串中出现的次数之和 题目分析:可以直接先用后缀数组跑出来height,再用RMQ跑出来任意两个后缀的height,我们可以将题意转换为求 ...

  8. URAL - 1297 Palindrome(后缀数组+RMQ)

    题目链接:点击查看 题目大意:给出一个字符串,求出最长的回文子串 题目分析:如果用以往的方法求,不可避免的都需要枚举所有子串,时间复杂度就已经到达了O(n),而后缀数组可以通过O(n)预处理后得到所有 ...

  9. hdu 5008 Boring String Problem(后缀数组+rmq)

    题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...

最新文章

  1. 《BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之44---QChat 技术...
  2. console线驱动安装_centos7安装docker
  3. CSS :hover 伪类
  4. java ntlm_使用java UrlConnection使用ntlm(或kerberos)进行身份验证
  5. 编译安装mysql 不动了_编译安装MySQL5.6失败的相关问题解决方案
  6. 关于如何理解链表结构体指针引用LinkNode * L的问题
  7. 【C++模块实现】| 【07】对于互斥、自旋锁、条件变量、信号量简介及封装
  8. 微信公号DIY:训练微信聊天机器人公号变身图片上传工具
  9. 频数直方图的步骤_超级详细的直方图应用步骤及分析,一篇搞定直方图!
  10. 华为智慧屏鸿蒙系统深度评测,八个维度深度评测华为荣耀智慧屏
  11. Android 百度地图--定位、周边搜索
  12. 用java写一个汽车加油的程序_Java实现 LeetCode 134 加油站
  13. 面试题 猜颜色球游戏
  14. 什么事件必须要我王二狗来处理?
  15. 最后完美解决pip没法用的问题
  16. 8款HTML5动画特效推荐源码
  17. 聊聊太阳能光伏发电系统的防雷设计
  18. 动环监控系统方案应用
  19. 元件的座位,艺术的走线-什么是PCB-PCB系列教程1-1
  20. 基于web的婚纱摄影网站的设计与实现

热门文章

  1. CORS 跨域-哪些操作受到同源限制
  2. CORS 跨域-哪些操作不受同源限制
  3. 被丢弃的消息不能再次出现
  4. condition.await
  5. 搜索引擎其实是一个读库
  6. 商品评价 - 实现分页
  7. 数据库-排序-升降序-多列
  8. tomcat_部署项目的方式
  9. 上传文件漏洞防御手段
  10. jvm_虚拟机参数讲解(三)