POJ 3693 (后缀数组) Maximum repetition substring
找重复次数最多的字串,如果有多解,要求字典序最小。
我也是跟着罗穗骞菊苣的论文才刷这道题的。
首先还是枚举一个循环节的长度L,如果它出现两次的话,一定会包含s[0], s[L], s[2L]这些相邻两个之间。
然后枚举相邻的两个,尽可能的向前和向后延伸,假设延伸长度为k,则重复次数为k / L + 1
向后延伸很自然的就是求一次LCP,这个用RMQ预处理一下就可以O(1)查询。
向前延伸就是考虑到,我们枚举的s[i*L]和s[(i+1)*L]并不一定是字串的开头,所以向前移动i - (k % i)个位置。
为什么向前移动这么多,就是因为这样的话,LCP的长度就正好是i的整数倍了。
所以向前移动以后,再求一次LCP,看看能否够i - (k % i)这么多,够的话这个串的重复次数再加1.
至于要字典序最小,就得用height数组天生自带字典序。把所有重复次数最多的长度记录下来,然后按字典序枚举,只要找到一组就输出。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = + ;
char s[maxn];
int n;
int sa[maxn], rank[maxn], height[maxn];
int t[maxn], t2[maxn], c[]; void build_sa(int n, int m)
{
int i, *x = t, *y = t2;
for(i = ; i < m; i++) c[i] = ;
for(i = ; i < n; i++) c[x[i] = s[i]]++;
for(i = ; i < m; i++) c[i] += c[i - ];
for(i = n - ; i >= ; i--) sa[--c[x[i]]] = i;
for(int k = ; k <= n; k <<= )
{
int p = ;
for(i = n - k; i < n; i++) y[p++] = i;
for(i = ; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
for(i = ; i < m; i++) c[i] = ;
for(i = ; i < n; i++) c[x[y[i]]]++;
for(i = ; i < m; i++) c[i] += c[i - ];
for(i = n - ; i >= ; i--) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = ; x[sa[]] = ;
for(i = ; i < n; i++)
x[sa[i]] = y[sa[i]]==y[sa[i-]] && y[sa[i]+k]==y[sa[i-]+k] ? p - : p++;
if(p >= n) break;
m = p;
}
} void build_height()
{
int k = ;
for(int i = ; i <= n; i++) rank[sa[i]] = i;
for(int i = ; i < n; i++)
{
if(k) k--;
int j = sa[rank[i] - ];
while(s[i + k] == s[j + k]) k++;
height[rank[i]] = k;
}
} int d[maxn][]; void init_RMQ()
{
for(int i = ; i < n; i++) d[i][] = height[i + ];
for(int j = ; ( << j) <= n; j++)
for(int i = ; i + ( << j) - < n; i++)
d[i][j] = min(d[i][j-], d[i + (<<(j-))][j-]);
} int RMQ(int L, int R)
{
int k = ;
while( ( << (k+)) <= (R - L + ) ) k++;
return min(d[L][k], d[R-(<<k)+][k]);
} int LCP(int i, int j)
{
i = rank[i] - ; j = rank[j] - ;
if(i > j) swap(i, j);
return RMQ(i + , j);
} int a[maxn], cnt, maxl; int main()
{
//freopen("in.txt", "r", stdin); int kase = ;
while(scanf("%s", s) == && s[] != '#')
{
n = strlen(s);
build_sa(n + , );
build_height();
init_RMQ(); cnt = maxl = ;
for(int i = ; i < n; i++)
{
for(int j = ; j + i < n; j += i)
{
int k = LCP(j, j + i);
int t = k / i + ;
int left = i - (k % i);
int head = j - left;
if(head >= && LCP(head, head + i) >= left) t++;
if(t > maxl)
{
cnt = ;
a[cnt++] = i;
maxl = t;
}
if(t == maxl) a[cnt++] = i;
}
} int len = -, st;
for(int i = ; i <= n && len == -; i++)
{
for(int j = ; j < cnt; j++)
{
int l = a[j];
if(LCP(sa[i], sa[i] + l) >= (maxl - ) * l)
{
len = l;
st = sa[i];
break;
}
}
} printf("Case %d: ", ++kase);
for(int i = ; i < len * maxl; i++) printf("%c", s[st + i]);
puts("");
} return ;
}
代码君
POJ 3693 (后缀数组) Maximum repetition substring的更多相关文章
- poj 3693 后缀数组 重复次数最多的连续重复子串
Maximum repetition substring Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8669 Acc ...
- POJ 3693 后缀数组
题目链接:http://poj.org/problem?id=3693 题意:首先定义了一个字符串的重复度.即一个字符串由一个子串重复k次构成.那么最大的k即是该字符串的重复度.现在给定一个长度为n的 ...
- [poj 3693]后缀数组+出现次数最多的重复子串
题目链接:http://poj.org/problem?id=3693 枚举长度L,看长度为L的子串最多能重复出现几次,首先,能出现1次是肯定的,然后看是否能出现两次及以上.由抽屉原理,这个子串出现次 ...
- POJ - 2406 ~SPOJ - REPEATS~POJ - 3693 后缀数组求解重复字串问题
POJ - 2406 题意: 给出一个字符串,要把它写成(x)n的形式,问n的最大值. 这题是求整个串的重复次数,不是重复最多次数的字串 这题很容易想到用KMP求最小循环节就没了,但是后缀数组也能写 ...
- POJ 3693 后缀数组+RMQ
思路: 论文题 后缀数组&RMQ 有一些题解写得很繁 //By SiriusRen #include <cmath> #include <cstdio> #includ ...
- POJ3693 Maximum repetition substring 后缀数组
POJ - 3693 Maximum repetition substring 题意 输入一个串,求重复次数最多的连续重复字串,如果有次数相同的,则输出字典序最小的 Sample input ccab ...
- POJ3693 Maximum repetition substring [后缀数组 ST表]
Maximum repetition substring Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9458 Acc ...
- POJ 3693 Maximum repetition substring(最多重复次数的子串)
Maximum repetition substring Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10461 Ac ...
- Maximum repetition substring 后缀数组
Maximum repetition substring Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7578 Acc ...
随机推荐
- 纯CSS3实现3D动画导航,html5 webRTC技术实现免费网页电话拨打
花了一周的时间完成了 说吧 (免费网页电话) 的前端开发工作,先将技术点总结如下: 免费电话采用最新的html5 webRTC 技术 实现互联网和电信MIS网互通实现网页电话,目前只有 google ...
- POJ 2080
import java.util.*; public class Main { public static void main(String args[]){ Scanner cin=new Scan ...
- [C++]不能被继承的类
前面讲到,派生类的构造函数和析构函数会自动调用基类的构造函数和析构函数,那么要让一个类不能被继承,那么就将它的构造函数和析构函数私有函数(派生类可以访问保护函数).那么怎样才能得到该类的实例呢? 这倒 ...
- WCF分布式开发步步为赢(6):WCF服务契约继承与分解设计
上一节我们学习了WCF分布式开发步步为赢(5)服务契约与操作重载部分.今天我们来继续学习WCF服务契约继承和服务分解设计相关的知识点.WCF服务契约继承有何优势和缺点?实际项目里契约设计有什么原则和依 ...
- PHP 反射机制Reflection
简介 PHP Reflection API是PHP5才有的新功能,它是用来导出或提取出关于类.方法.属性.参数等的详细信息,包括注释. class Reflection { } interface R ...
- malloc/free 和 new/delete 的区别
1.malloc在C和C++中的区别 1.1.C中可以将任意的指针赋值给void*类型的变量.也可以将void*类型的值赋值给通常的指针变量. ---------------------------- ...
- J-link V8固件升级记
http://blog.sina.com.cn/s/blog_5bdee3020101khfy.html 好久没为电子工程事业尽份力了!今天也稍微努把力!写写我是如何升级J-link的固件的吧! J- ...
- Centos环境下部署游戏服务器-SVN
版本控制工具的文章已经被写滥了,所以本篇文章不想介绍如何安装Svn如何可视化操作这些东西.本篇文章讲述我自己对Svn的理解,以及在命令行下操作.为啥不应可视化界面?有两方面的原因,远程登录到服务器都是 ...
- 机器人学 —— 机器人感知(Gaussian Model)
机器人感知是UPNN机器人专项中的最后一门课程,其利用视觉方法来对环境进行感知.与之前提到的机器人视觉不同,机器人感知更侧重于对环境物体的识别与检测.与计算机视觉不同,机器人视觉所识别的物体往往不需要 ...
- JQuery获取浏览器窗口的高度和宽度
<script type="text/javascript"> $(document).ready(function() { alert($(window).heigh ...