传送门:POJ - 3693  

题意:给你一个字符串,求重复次数最多的连续重复子串,如果有一样的,取字典序小的字符串。

题解:

比较容易理解的部分就是枚举长度为L,然后看长度为L的字符串最多连续出现几次。既然长度为L的串重复出现,那么str[0],str[l],str[2*l]……中肯定有两个连续的出现在字符串中。

那么就枚举连续的两个,然后从这两个字符前后匹配,看最多能匹配多远。即以str[i*l],str[i*l+l]前后匹配,这里是通过查询suffix(i*l),suffix(i*l+l)的最长公共前缀。通过rank值能找到i*l,与i*l+l的排名,我们要查询的是这段区间的height的最小值,通过RMQ预处理达到查询为0(1)的复杂度

设LCP长度为M, 则答案显然为M / L + 1, 但这不一定是最好的, 因为答案的首尾不一定再我们枚举的位置上. 我的解决方法是, 我们考虑M % L的值的意义, 我们可以认为是后面多了M % L个字符, 但是我们更可以想成前面少了(L - M % L)个字符! 所以我们求后缀j * L - (L - M % L)与后缀(j+ 1) * L - (L - M % L)的最长公共前缀。即把之前的区间前缀L-M%L即可。

然后把可能取到最大值的长度L保存,由于 题目要求字典序最小,通过sa数组进行枚举,取到的第一组,肯定是字典序最小的。

题解的出处:https://blog.csdn.net/acm_cxlove/article/details/7941205

  1 #include<cstdio>
2 #include<algorithm>
3 #include<queue>
4 #include<iostream>
5 #include<cmath>
6 #include<cstring>
7 using namespace std;
8
9 const int maxn = 1e5+10;
10 int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
11 int rnk[maxn],height[maxn];
12 char s[maxn];
13 int r[maxn];
14
15 //sa:字典序中排第i位的起始位置在str中第sa[i] sa[1~n]为有效值
16
17 //rnk:就是str第i个位置的后缀是在字典序排第几 rnk[0~n-1]为有效值
18
19 //height:字典序排i和i-1的后缀的最长公共前缀 height[2~n]为有效值,第二个到最后一个
20
21 int cmp(int *r,int a,int b,int k)
22 {
23 return r[a]==r[b]&&r[a+k]==r[b+k];
24 }
25
26 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长
27 {
28 int i,j,p,*x=wa,*y=wb,*t;
29 for(i=0; i<m; i++) wsf[i]=0;
30 for(i=0; i<=n; i++) wsf[x[i]=r[i]]++;
31 for(i=1; i<m; i++) wsf[i]+=wsf[i-1];
32 for(i=n; i>=0; i--) sa[--wsf[x[i]]]=i;
33 p=1;
34 j=1;
35 for(; p<=n; j*=2,m=p){
36 for(p=0,i=n+1-j; i<=n; i++) y[p++]=i;
37 for(i=0; i<=n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
38 for(i=0; i<=n; i++) wv[i]=x[y[i]];
39 for(i=0; i<m; i++) wsf[i]=0;
40 for(i=0; i<=n; i++) wsf[wv[i]]++;
41 for(i=1; i<m; i++) wsf[i]+=wsf[i-1];
42 for(i=n; i>=0; i--) sa[--wsf[wv[i]]]=y[i];
43 swap(x,y);
44 x[sa[0]]=0;
45 for(p=1,i=1; i<=n; i++)
46 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
47 }
48 }
49
50 void getheight(int *r,int n)//n为添加0后的总长
51 {
52 int i,j,k=0;
53 for(i=1; i<=n; i++) rnk[sa[i]]=i;
54 for(i=0; i<n; i++){
55 if(k)
56 k--;
57 else
58 k=0;
59 j=sa[rnk[i]-1];
60 while(r[i+k]==r[j+k])
61 k++;
62 height[rnk[i]]=k;
63 }
64 }
65
66 int dp[maxn][40];
67
68 void rmq_init(int n){
69
70 int m=floor(log(n+0.0)/log(2.0));
71 for(int i=1;i<=n;i++)dp[i][0]=height[i];
72 for(int j=1;j<=m;j++){
73 for(int i=n;i;i--){
74 dp[i][j]=dp[i][j-1];
75 if(i+(1<<(j-1))<=n){
76 dp[i][j]=min(dp[i][j],dp[i+(1<<(j-1))][j-1]);
77 }
78 }
79 }
80 }
81
82 int rmq(int l,int r){
83
84 int a=rnk[l],b=rnk[r];
85 if(a>b)swap(a,b);
86 a++;
87 int k=floor(log(b-a+1.0)/log(2.0));
88 return min(dp[a][k],dp[b-(1<<k)+1][k]);
89 }
90
91 int main()
92 {
93 ios::sync_with_stdio(false);
94 cin.tie(0);
95 cout.tie(0);
96 int t=1;
97 while(cin>>s){
98 if(s[0]=='#') break;
99 int len=strlen(s);
100 for(int i=0;i<len;i++) r[i]=s[i]-'a'+1;
101 r[len]=0;
102 getsa(r,sa,len,150);
103 getheight(r,len);
104 rmq_init(len);
105 int ans=0;
106 int pos=0,p=0;
107 for(int k=1;k<len;k++){ //枚举长度
108 for(int i=0;i+k<len;i+=k){ //第i段
109 int n=rmq(i,i+k); //每一段的公共前缀最小值
110 n--;
111 for(int j=0;j<=k-1;j++){ //枚举每一段的起点
112 int now=i-j;
113 if((now<0||s[now]!=s[now+k])&&j) break;
114 n++;
115 int sum=n/k+1;
116 if(sum>ans||(sum==ans&&rnk[now]<rnk[pos])){
117 ans=sum;
118 pos=now;
119 p=k;
120 }
121 }
122 }
123 }
124 cout<<"Case "<<t++<<": ";
125 if(ans<=1){
126 char tmp='z';
127 for(int i=0;i<len;i++) tmp=min(tmp,s[i]);
128 cout<<tmp<<endl;
129 }
130 else{
131 for(int i=0;i<ans*p;i++){
132 cout<<s[i+pos];
133 }
134 cout<<endl;
135 }
136 }
137 return 0;
138 }

POJ - 3693 Maximum repetition substring(重复次数最多的连续重复子串)的更多相关文章

  1. 【POJ 3693】Maximum repetition substring 重复次数最多的连续重复子串

    后缀数组的论文里的例题,论文里的题解并没有看懂,,, 求一个重复次数最多的连续重复子串,又因为要找最靠前的,所以扫的时候记录最大的重复次数为$ans$,扫完后再后从头暴力扫到尾找重复次数为$ans$的 ...

  2. POJ3693 Maximum repetition substring —— 后缀数组 重复次数最多的连续重复子串

    题目链接:https://vjudge.net/problem/POJ-3693 Maximum repetition substring Time Limit: 1000MS   Memory Li ...

  3. POJ 3693 Maximum repetition substring(连续重复子串)

    http://poj.org/problem?id=3693 题意:给定一个字符串,求重复次数最多的连续重复子串. 思路: 这道题确实是搞了很久,首先枚举连续子串的长度L,那么子串肯定包含了r[k], ...

  4. poj 3693 后缀数组 重复次数最多的连续重复子串

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8669   Acc ...

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

    Description The repetition number of a string is defined as the maximum number R such that the strin ...

  6. POJ-3693-Maximum repetition substring(后缀数组-重复次数最多的连续重复子串)

    题意: 给出一个串,求重复次数最多的连续重复子串 分析: 比较容易理解的部分就是枚举长度为L,然后看长度为L的字符串最多连续出现几次. 既然长度为L的串重复出现,那么str[0],str[l],str ...

  7. 后缀数组 POJ 3693 Maximum repetition substring

    题目链接 题意:给定一个字符串,求重复次数最多的连续重复子串. 分析:(论文上的分析)先穷举长度 L,然后求长度为 L 的子串最多能连续出现几次.首先连续出现 1 次是肯定可以的,所以这里只考虑至少 ...

  8. spoj687 后缀数组重复次数最多的连续重复子串

    REPEATS - Repeats no tags  A string s is called an (k,l)-repeat if s is obtained by concatenating k& ...

  9. SPOJ - REPEATS —— 后缀数组 重复次数最多的连续重复子串

    题目链接:https://vjudge.net/problem/SPOJ-REPEATS REPEATS - Repeats no tags  A string s is called an (k,l ...

随机推荐

  1. Java基础-数据类型及变量

    Java基本语法 1.标识符(zhi) 含义:名字 类名.对象名.方法名.变量名.常量名-- 一个合法的标识符的组成:数字.字母._和$ 注意事项: 不能重复 不能以数字开头 区分大小写 不能以关键字 ...

  2. LeetCode700 二叉搜索树中搜索

    给定二叉搜索树(BST)的根节点和一个值. 你需要在BST中找到节点值等于给定值的节点. 返回以该节点为根的子树. 如果节点不存在,则返回 NULL. 例如, 给定二叉搜索树: 4 / \ 2 7 / ...

  3. JVM-Class文件的结构

    Class类文件的结构 Class文件是一株以8个字节为单位的二进制流.各个数据项目严格按照顺序紧凑的排列在文件之中,中间没有任何的分隔符,当遇到占用的空间大于8个字节时,会按照高位在前的方式进行分割 ...

  4. 【ORA】ORA-27090: Unable to reserve kernel resources for asynchronous disk I/O

    操作系统是CentOS 5.11 数据库 10.2.0.5.0 晚上查看数据库,发现数据库报错查看相关的trace文件内容如下: *** SERVICE NAME:(SYS$BACKGROUND) 2 ...

  5. cut和tr命令的联合使用

    cut的-d选项只能是单个字符,而对于多个连续相同字符分隔的字段,单凭cut命令是达不到想要的效果的,特别是多个连续空格分隔时. 但借助tr -s的压缩重复字符功能,可以将多个连续空格压缩为一个空格, ...

  6. 使用 gRPC-UI 调试.NET 5的gPRC服务

    在上一篇文章中,我介绍了gRPCurl一个命令行工具,该工具可用于测试gRPC服务的端点,在本文中,我将向您介绍 gRPC-ui, 它可以作为Web工具使用,有点像Postman,但用于gRPC AP ...

  7. RabbitMQ六种工作模式有哪些?怎样用SpringBoot整合RabbitMQ

    目录 一.RabbitMQ入门程序 二.Work queues 工作模式 三.Publish / Subscribe 发布/订阅模式 四.Routing 路由模式 五.Topics 六.Header ...

  8. LTH7锂电池充放电IC完整方案

    内容目录: A,LTH7贴片5脚充电芯片    PW4054 1, 单节的锂电池保护电路     单节为3.7V锂电池(也叫4.2V)和3.8V锂电池(也叫4.35V) 2, 单节的锂电池充电电路   ...

  9. python_mmdt:一种基于敏感哈希生成特征向量的python库(一)

    概述 python_mmdt是一种基于敏感哈希的特征向量生成工具.核心算法使用C实现,提高程序执行效率.同时使用python进行封装,方便研究人员使用. 本篇幅主要介绍涉及的相关基本内容与使用,相关内 ...

  10. 为什么MySQL索引使用B+树

    为什么MySQL索引使用B+树 聚簇索引与非聚簇索引 不同的存储引擎,数据文件和索引文件位置是不同的,但是都是在磁盘上而不是内存上,根据索引文件.数据文件是否放在一起而有了分类: 聚簇索引:数据文件和 ...