poj 3693 Maximum repetition substring (后缀数组)
其实是论文题。。
题意:求一个字符串中,能由单位串repeat得到的子串中,单位串重复次数最多的子串。若有多个重复次数相同的,输出字典序最小的那个。
解题思路:其实跟论文差不多,我看了很久没看懂,后来总算理解了一些。假设我们的单位串长度为l,那么我们将串划分为s[0] , s[l] , s[2*l] , s[3*l]。。这样,可以根据l划分为n/l段。枚举一个j,表示当前枚举的位置为s[j*l],我们要做的是,求suf[j*l]跟suf[(j+1)*l]的lcp (这里用rmq做,询问是o(1)的),假设这个lcp是k,那我们知道,从s[j*l]开始的,以l为单位长度的repeat次数至少是k/l + 1,这是为什么呢?想想lcp的意思,应该能想通的。但这样并不一定是最优的,因为我们如果往前推,有可能还有一些是相同的,那就往前枚举i,表示前i个也是相同的,一直枚举到不同,或者额外增加的长度超过l为止(超过l就相当于是上一个j了)。这时,我们的新的lcp长度k=k+i了,用这个k去计算repeat次数才是正确的。遍历过程中,我们要把取到最大repeat次数的l记下来,求字典序最小时,就按rank从小到大枚举开头,然后看有没有记下的l中,在当前开头的字符串是符合最大repeat次数的(用lcp再判断一次好了),一旦找到符合的,就输出好了。
没写case,一直错,一直找不到错哪儿,泪奔了。。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std ;
const int maxn = 511111 ; int p[maxn] ;
int min ( int a , int b ) { return a < b ? a : b ; }
int dp[25][maxn] , f[maxn] , ans , fuck ; vector<int>vec ;
struct Suf{
int wa[maxn] , wb[maxn] , ws[maxn] , wv[maxn] ;
int rank[maxn] , hei[maxn] , sa[maxn] ; int cmp ( int *r , int i , int j , int l ){ return r[i] == r[j] && r[i+l] == r[j+l] ; } void da ( int *r , int n , int m ){
int *x = wa , *y = wb , *t ;
int i , j , k , p ;
for ( i = 0 ; i < m ; i ++ ) ws[i] = 0 ;
for ( i = 0 ; i < n ; i ++ ) ws[x[i]=r[i]] ++ ;
for ( i = 1 ; i < m ; i ++ ) ws[i] += ws[i-1] ;
for ( i = n - 1 ; i >= 0 ; i -- ) sa[--ws[x[i]]] = i ;
for ( j = 1 , p = 1 ; p < n ; j *= 2 , m = p ) {
for ( p = 0 , 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 ++ ) ws[i] = 0 ;
for ( i = 0 ; i < n ; i ++ ) ws[x[i]] ++ ;
for ( i = 1 ; i < m ; i ++ ) ws[i] += ws[i-1] ;
for ( i = n - 1 ; i >= 0 ; i -- ) sa[--ws[x[y[i]]]] = y[i] ;
for ( t = x , x = y , y = t ,x[sa[0]] = 0 , p = 1 , i = 1 ; i < n ; i ++ )
x[sa[i]] = cmp ( y , sa[i-1] , sa[i] , j ) ? p - 1 : p ++ ;
}
k = 0 ;
for ( i = 1 ; i < n ; i ++ ) rank[sa[i]] = i ;
for ( i = 0 ; i < n - 1 ; hei[rank[i++]] = k )
for ( k ? k -- : 0 , j = sa[rank[i]-1] ; r[i+k] == r[j+k] ; k ++ ) ;
} void rmq ( int n ) {
int i , j ;
for ( i = 1 ; i <= n ; i ++ ) dp[0][i] = hei[i] ;
for ( i = 1 ; i <= 20 ; i ++ )
for ( j = 1 ; j + ( 1 << i ) - 1 <= n ; j ++ )
dp[i][j] = min ( dp[i-1][j] , dp[i-1][j+(1<<(i-1))] ) ;
} int query ( int l , int r ) {
if ( l > r ) swap ( l , r ) ;
l ++ ;//要从height[l+1]到height[r]之间求最小值
if ( l == r ) return dp[0][l] ;
int k = r - l + 1 ;
return min ( dp[f[k]][l] , dp[f[k]][r-(1<<f[k])+1] ) ;
} void solve ( int n , char *s ) {
rmq ( n ) ;
int i , j , k , l , r ;
for ( l = 1 ; l < n ; l ++ )
for ( j = 0 ; j < n / l ; j ++ ) {
int pos1 = j * l , pos2 = j * l + l ;
k = query ( rank[pos1] , rank[pos2] ) ;
i = 0 ;
if ( j != 0 ) {
while ( i < l && s[pos1-i-1] == s[pos2-i-1] ) i ++ ;
}
k += i ;
int add = k / l + 1 ;
if ( add == ans ) vec.push_back ( l ) ;
if ( add > ans ) {
ans = add ;
vec.clear () ;
vec.push_back ( l ) ;
}
}
int flag ;
for ( i = 1 ; i <= n ; i ++ ) {
flag = 0 ;
for ( j = 0 ; j < vec.size () ; j ++ ) {
l = vec[j] ;
k = query ( i , rank[sa[i]+l] ) ;
if ( k / l + 1 == ans ) {
for ( r = 0 ; r < ans * l ; r ++ )
printf ( "%c" , s[sa[i]+r] ) ;
puts ( "" ) ;
flag = 1 ;
break ;
}
}
if ( flag ) break ;
}
} } arr ; char s1[maxn] ;
int s[maxn] ; int main () {
int cas , n , i , j , ca = 0 ;
j = 0 ;
for ( i = 1 ; i < maxn - 1111 ; i ++ ) {
if ( i > 1 << j + 1 ) j ++ ;
f[i] = j ;
}
scanf ( "%d" , &cas ) ;
while ( cas -- ) {
scanf ( "%s" , s1 ) ;
if ( s1[0] == '#' ) break ;
vec.clear () ;
ans = 1 ;
n = strlen ( s1 ) ;
int len = 0 ;
for ( i = 0 ; i < n ; i ++ ) s[i] = s1[i] ;
s[n] = 0 ;
arr.da ( s , n + 1 , 555 ) ;
printf ( "Case %d: " , ++ca ) ;
arr.solve ( n , s1 ) ;
}
}
poj 3693 Maximum repetition substring (后缀数组)的更多相关文章
- POJ 3693 Maximum repetition substring ——后缀数组
重复次数最多的字串,我们可以枚举循环节的长度. 然后正反两次LCP,然后发现如果长度%L有剩余的情况时,答案是在一个区间内的. 所以需要找到区间内最小的rk值. 两个后缀数组,四个ST表,$\Thet ...
- POJ 3693 Maximum repetition substring (后缀数组+RMQ)
题意:给定一个字符串,求其中一个由循环子串构成且循环次数最多的一个子串,有多个就输出最小字典序的. 析:枚举循环串的长度ll,然后如果它出现了两次,那么它一定会覆盖s[0],s[ll],s[ll*2] ...
- 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 ...
- POJ3693 Maximum repetition substring —— 后缀数组 重复次数最多的连续重复子串
题目链接:https://vjudge.net/problem/POJ-3693 Maximum repetition substring Time Limit: 1000MS Memory Li ...
- POJ 3693 Maximum repetition substring(后缀数组)
Description The repetition number of a string is defined as the maximum number R such that the strin ...
- POJ 3693 Maximum repetition substring(后缀数组+ST表)
[题目链接] poj.org/problem?id=3693 [题目大意] 求一个串重复次数最多的连续重复子串并输出,要求字典序最小. [题解] 考虑错位匹配,设重复部分长度为l,记s[i]和s[i+ ...
随机推荐
- uva 111 - History Grading (dp, LCS)
题目链接 题意:给N,第二行是答案,n个数c1---cn, 代表第一个的顺序是c1,第二个数顺序是c2; 下面每一行是学生的答案,格式同上. 注意:这个给的顺序需要处理一下,不能直接用. 思路:LCS ...
- Sass结合Modernizr的使用方法
Modernizr在初始化的时候会首先找寻class=“no-js”的元素: <!DOCTYPE html> <html class="no-js"> &l ...
- PHP查询数据库中满足条件的记录条数(二种实现方法)
在需要输出网站用户注册数或者插入数据之前判断是否有重复记录时,就需要获取满足条件的MySQL查询的记录数目,接下来介绍两种查询统计方法,感兴趣的朋友可以了解下啊,或许对你有所帮助 在需要输出网 ...
- POJ 3041 Asteroids (最小点覆盖集)
题意 给出一个N*N的矩阵,有些格子上有障碍,要求每次消除一行或者一列的障碍,最少消除多少次可以全部清除障碍. 思路 把关键点取出来:一个障碍至少需要被它的行或者列中的一个消除. 也许是最近在做二分图 ...
- LeetCode Linked List Cycle 单链表环
题意:给一个单链表,判断其是否出现环! 思路:搞两个指针,每次,一个走两步,另一个走一步.若有环,他们会相遇,若无环,走两步的指针必定会先遇到NULL. /** * Definition for si ...
- UVA 10537 The Toll! Revisited 过路费(最短路,经典变形)
题意:给一个无向图,要从起点s运送一批货物到达终点e,每个点代表城镇/乡村,经过城镇需要留下(num+19)/20的货物,而经过乡村只需要1货物即可.现在如果要让p货物到达e,那么从起点出发最少要准备 ...
- cbitmap 获取RGB CBitMap的用法
MFC提供了位图处理的基础类CBitmap,可以完成位图(bmp图像)的创建.图像数据的获取等功能.虽然功能比较少,但是在对位图进行一些简单的处理时,CBitmap类还是可以胜任的.很多人可能会采用一 ...
- Table '.\mysql\proc' is marked as crashed and should be repaired 报错
Table '.\mysql\proc' is marked as crashed and should be repaired 报错 解决方法: 找到mysql的安装目录的bin/myisamchk ...
- win7/8下VirtualBox虚拟共享文件夹设置
1. 安装增强功能包(VBoxGuestAdditions) 打开虚拟机,运行ubuntu,在菜单栏选择"设备->安装增强功能",根据提示即可安装成功(成功后也可 以实现 ...
- 【转】Android开发学习笔记:5大布局方式详解
Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件. 帧布局(FrameLayout):组件从屏幕左上方布局组件. 表格布局(Tabl ...