【poj3693】 Maximum repetition substring
http://poj.org/problem?id=3693 (题目链接)
题意
给定一个字符串,求重复次数最多的连续重复子串,若存在多组解,输出字典序最小的。
Solution
后缀数组论文题,就是加了个字典序要求。
先穷举长度 L,然后求长度为 L 的子串最多能连续出现几次。首先连续出现 1 次是肯定可以的,所以这里只考虑至少 2 次的情况。假设在原字符串中连续出 现 2 次,记这个子字符串为 S,那么 S 肯定包括了字符 r[0], r[L], r[L*2], r[L*3], ……中的某相邻的两个。所以只须看字符 r[L*i]和 r[L*(i+1)]往前和 往后各能匹配到多远,记这个总长度为 K,那么这里连续出现了 K/L+1 次。最后 看最大值是多少。如图:
穷举长度 L 的时间是 n,每次计算的时间是 n/L。所以整个做法的时间复杂 度是 O(n/1+n/2+n/3+……+n/n)=O(nlogn)。
正着求一遍sa就可以算出r,反着求一遍sa就可以算出l。
对于字典序最小,我们考虑求出一个连续段以后,如果它的两端没有被卡死,也就是说它仍然可以在一定的区间内滑动,我们可以通过后缀的排名取到字典序最小的那个。这个操作可以用ST表维护。
于是就要写2个后缀数组,3个ST表,mdzz题→_→
细节
一个很重要的细节,反向字符串赋值的时候,要把第n+1位清为0,不然求后缀数组的时候会出问题。
为什么我ST表总是写错→_→
代码
// poj3693
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=100010;
char s1[maxn],s2[maxn];
int sa1[maxn],sa2[maxn],rank1[maxn],rank2[maxn],height1[maxn],height2[maxn];
int bin[30],Log[maxn],st1[maxn][30],st2[maxn][30],str[maxn][30]; namespace Suffix {
int wa[maxn],wb[maxn],ww[maxn];
bool cmp(int *r,int a,int b,int l) {
return r[a]==r[b] && r[a+l]==r[b+l];
}
void da(char *r,int *sa,int n,int m) {
int i,j,p,*x=wa,*y=wb;
for (i=0;i<=m;i++) ww[i]=0;
for (i=1;i<=n;i++) ww[x[i]=r[i]]++;
for (i=1;i<=m;i++) ww[i]+=ww[i-1];
for (i=n;i>=1;i--) sa[ww[x[i]]--]=i;
for (p=0,j=1;p<n;j*=2,m=p) {
for (p=0,i=n-j+1;i<=n;i++) y[++p]=i;
for (i=1;i<=n;i++) if (sa[i]>j) y[++p]=sa[i]-j;
for (i=0;i<=m;i++) ww[i]=0;
for (i=1;i<=n;i++) ww[x[y[i]]]++;
for (i=1;i<=m;i++) ww[i]+=ww[i-1];
for (i=n;i>=1;i--) sa[ww[x[y[i]]]--]=y[i];
for (swap(x,y),p=x[sa[1]]=1,i=2;i<=n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p : ++p;
}
}
void calheight(char *r,int *sa,int *height,int *rank,int n) {
for (int i=1;i<=n;i++) rank[sa[i]]=i;
for (int k=0,i=1;i<=n;i++) {
if (k) k--;
int j=sa[rank[i]-1];
while (r[i+k]==r[j+k]) k++;
height[rank[i]]=k;
}
}
}
int query1(int x,int y) {
if (x>y) swap(x,y);x++;
int k=Log[y-x+1];
return min(st1[x][k],st1[y-bin[k]+1][k]);
}
int query2(int x,int y) {
if (x>y) swap(x,y);x++;
int k=Log[y-x+1];
return min(st2[x][k],st2[y-bin[k]+1][k]);
}
int minr(int x,int y) {
return rank1[x]<rank1[y] ? x : y;
}
int queryr(int x,int y) {
int k=Log[y-x+1];
return minr(str[x][k],str[y-bin[k]+1][k]);
}
int main() {
int Case=0;
bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
for (int i=2;i<=100000;i++) Log[i]=Log[i>>1]+1;
using namespace Suffix;
while (scanf("%s",s1+1)!=EOF && s1[1]!='#') {
int n=strlen(s1+1);
s2[n+1]='\0'; //important
for (int i=1;i<=n;i++) s2[n-i+1]=s1[i];
da(s1,sa1,n,300);
da(s2,sa2,n,300);
calheight(s1,sa1,height1,rank1,n);
calheight(s2,sa2,height2,rank2,n);
for (int i=1;i<=n;i++) st1[i][0]=height1[i],st2[i][0]=height2[i];
for (int i=1;i<=n;i++) str[i][0]=i;
for (int j=1;j<=20;j++)
for (int i=1;i+bin[j]<=n+1;i++) {
st1[i][j]=min(st1[i][j-1],st1[i+bin[j-1]][j-1]);
st2[i][j]=min(st2[i][j-1],st2[i+bin[j-1]][j-1]);
str[i][j]=minr(str[i][j-1],str[i+bin[j-1]][j-1]);
}
int ansl=1,ansr=1,cnt=1;
for (int i=2;i<=n;i++) if (s1[i]<s1[ansl]) ansl=ansr=i;
for (int k=1;k<=n;k++)
for (int i=1;i*k+1<=n;i++) {
int x=(i-1)*k+1,y=i*k+1;
int r=query1(rank1[x],rank1[y]);
int l=query2(rank2[n-x+1],rank2[n-y+1]);
int K=r+l+k-1;
if (K/k>=cnt && K/k>1) {
int s=queryr(x-l+1,x-l+1+K%k);
if (K/k==cnt) s=minr(s,ansl);
ansl=s,ansr=s+K/k*k-1;cnt=K/k;
}
}
printf("Case %d: ",++Case);
for (int i=ansl;i<=ansr;i++)
printf("%c",s1[i]);
puts("");
}
return 0;
}
【poj3693】 Maximum repetition substring的更多相关文章
- 【poj3693】Maximum repetition substring(后缀数组+RMQ)
题意:给定一个字符串,求重复次数最多的连续重复子串. 传说中的后缀数组神题,蒟蒻真的调了很久才对啊.感觉对后缀数组和RMQ的模版都不是很熟,导致还是会有很多各种各样的小错误= = 首先,枚举重复子串的 ...
- 【POJ3693】Maximum repetition substring (SA)
这是一道神奇的题目..论文里面说得不清楚,其实是这样...如果一个长度为l的串重复多次,那么至少s[1],s[l+1],s[2*l+1],..之中有相邻2个相等...设这时为j=i*l+1,k=j+l ...
- 【Poj-3693】Maximum repetition substring 后缀数组 连续重复子串
POJ - 3693 题意 SPOJ - REPEATS的进阶版,在这题的基础上输出字典序最小的重复字串. 思路 跟上题一样,先求出最长的重复次数,在求的过程中顺便纪录最多次数可能的长度. 因为sa数 ...
- 【SPOJ687&POJ3693】Maximum repetition substring(后缀数组)
题意: n<=1e5 思路: From http://hzwer.com/6152.html 往后匹配多远 r 用ST表求lcp即可...往前 l 就把串反过来再做一下.. 但是有可能求出来的最 ...
- 【po3693】Maximum repetition substring
题意: 给定一个字符串 求重复次数最多的连续重复子串 并输出字典序最小方案 题解: 枚举子串长度L 显然如果重复次数>1 那么答案串肯定包含s[1],s[1+L],s[1+L*2],...中的两 ...
- 【POJ 3693】Maximum repetition substring 重复次数最多的连续重复子串
后缀数组的论文里的例题,论文里的题解并没有看懂,,, 求一个重复次数最多的连续重复子串,又因为要找最靠前的,所以扫的时候记录最大的重复次数为$ans$,扫完后再后从头暴力扫到尾找重复次数为$ans$的 ...
- POJ-3693/HDU-2459 Maximum repetition substring 最多重复次数的子串(需要输出具体子串,按字典序)
http://acm.hdu.edu.cn/showproblem.php?pid=2459 之前hihocoder那题可以算出最多重复次数,但是没有输出子串.一开始以为只要基于那个,每次更新答案的时 ...
- POJ3693 Maximum repetition substring —— 后缀数组 重复次数最多的连续重复子串
题目链接:https://vjudge.net/problem/POJ-3693 Maximum repetition substring Time Limit: 1000MS Memory Li ...
- POJ3693 Maximum repetition substring [后缀数组 ST表]
Maximum repetition substring Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9458 Acc ...
随机推荐
- jQuery对底部导航进行跳转并高亮显示
这两天弄一个mui的底部菜单,有点费时了,尝试了用vue写,纯js写,还有根据mui的写,还是有些问题和麻烦.直到看了网上的一些例子,才想明白,之前一直是一种点击触发事件才高亮的思维去做,这个虽然可以 ...
- Oracle-归档日志详解(运行模式、分类)
一.Oracle日志分类 分三大类: Alert log files--警报日志,Trace files--跟踪日志(用户和进程)和 redo log 重做日志(记录数据库的更改 ...
- 20155330 《网络对抗》 Exp6 信息搜集与漏洞扫描
20155330 <网络对抗> Exp6 信息搜集与漏洞扫描 基础问题回答 哪些组织负责DNS,IP的管理? 互联网名称与数字地址分配机构(The Internet Corporation ...
- 12、JAVA内存模型与线程
一.JMM 有序性,可见性,原子性 synchorize :3个性都有: volatile:保证可见性+禁止指令重排: 二.线程的五种状态 面向过程与面向对象的差别 面向过程:站在计算机的角度分析和解 ...
- mfc 纯虚函数和抽象类
纯虚函数 抽像类 一.纯虚函数 虚函数为了重载和多态的需要,有时需要在基类中定义一个纯虚函数,代码部分在子类中加以实现.定义格式如下的函数我们称为纯虚函数: ; 纯虚函数与空虚函数是有区别的; 二.抽 ...
- 表单设置 disabled 后无法传值到后台的解决办法
在提交 from 表单时,下面的 input 无法正常提交给后台, 发现,如果input的字段设为disabled,该表单是无法提交的. <input type="text" ...
- [UOJ#461]新年的Dog划分[二分图染色、二分]
题意 给你一张无向连通图,你并不知道有哪些边,你首先要回答这张图是否是二分图,如果是,回答这张图黑白染色过后的任意一个点集.你需要在2000次询问内找到结果,每次你可以询问原图中一个边集删掉后是否还连 ...
- C语言与数据库操作入门
https://blog.csdn.net/flyingqd/article/details/78763652 C语言与数据库操作入门(Win版) 2017年12月10日 17:30:17 阅读数:1 ...
- Monkey稳定性测试
1.环境准备:Android SDK环境配置 2.手机连接/模拟器连接 : 1)手机打开开发者模式并允许USB连接 2)校验手机是否连接:打开cmd 输入 adb devices 3.查找apk包名及 ...
- idou老师教你学Istio 17 : 通过HTTPS进行双向TLS传输
众所周知,HTTPS是用来解决 HTTP 明文协议的缺陷,在 HTTP 的基础上加入 SSL/TLS 协议,依靠 SSL 证书来验证服务器的身份,为客户端和服务器端之间建立“SSL”通道,确保数据运输 ...