这也是一道例题

给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠。
算法分析:
这题的做法和上一题差不多,也是先二分答案,然后将后缀分成若干组。不
同的是,这里要判断的是有没有一个组的后缀个数不小于 k。如果有,那么存在
k 个相同的子串满足条件,否则不存在。这个做法的时间复杂度为 O(nlogn)。

我们可以通过二分子串的长度k来做,这时就将题目变成了是否存在重复次数至少为K次且长度不小k的字符串。

首先我们可以把相邻的所有不小于k的height[]看成一组,这组内有多少个字符串,

就相当于有多少个长度至少为k的重复的子串。

之所以可以这么做,是因为排名第i的字符串和排名第j的字符串的最长公共前缀

等于height[i],height[i+1],...,height[j]中的最小值,所以把所有不小于k的height[]看成

一组就保证了组内任意两个字符串的最长公共前缀都至少为k,且长度为k的前缀是每个字符串共有的,

因此这组内有多少个字符串,就相当于有多少个长度至少为k的重复的子串(任意一个子串都是某个后缀的前缀)。

Source Code:

//#pragma comment(linker, "/STACK:16777216") //for c++ Compiler
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cmath>
#include <stack>
#include <string>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <vector>
#include <algorithm>
#define Max(a,b) (((a) > (b)) ? (a) : (b))
#define Min(a,b) (((a) < (b)) ? (a) : (b))
#define Abs(x) (((x) > 0) ? (x) : (-(x)))
#define MOD 1000000007
#define pi acos(-1.0) using namespace std; typedef long long ll ;
typedef unsigned long long ull ;
typedef unsigned int uint ;
typedef unsigned char uchar ; template<class T> inline void checkmin(T &a,T b){if(a>b) a=b;}
template<class T> inline void checkmax(T &a,T b){if(a<b) a=b;} const double eps = 1e- ;
const int N = ;
const int M = ;
const ll P = 10000000097ll ;
const int INF = 0x3f3f3f3f ; int a[M], sa[M], h[M], rank[M]; void radix(int *str, int *a, int *b, int n, int m){
static int count[M];
int i;
memset(count, , sizeof(count));
for(i = ; i < n; ++i) ++count[str[a[i]]];
for(i = ; i <= m; ++i) count[i] += count[i - ];
for(i = n - ; i >= ; --i) b[--count[str[a[i]]]] = a[i];
} void suffix_array(int *str, int *sa, int n, int m){
static int a[M], b[M];
int i, j;
for(i = ; i < n; ++i) rank[i] = i;
radix(str, rank, sa, n, m); rank[sa[]] = ;
for(i = ; i < n; ++i) rank[sa[i]] = rank[sa[i - ]] + (str[sa[i]] != str[sa[i - ]]);
for(i = ; <<i < n; ++i){
for(j = ; j < n; ++j){
a[j] = rank[j] + ;
b[j] = j + ( << i) >= n ? : rank[j + ( << i)] + ;
sa[j] = j;
}
radix(b, sa, rank, n, n);
radix(a, rank, sa, n, n);
rank[sa[]] = ;
for(j = ; j < n; ++j){
rank[sa[j]] = rank[sa[j - ]] + (a[sa[j - ]] != a[sa[j]] || b[sa[j - ]] != b[sa[j]]);
}
}
} void calc_height(int *str, int *sa, int *h, int n){
int i, k = ;
h[] = ;
for(i = ; i < n; ++i){
k = k == ? : k - ;
if(rank[i] != ){
while(str[i + k] == str[sa[rank[i] - ] + k]){
++k;
}
}
h[rank[i]] = k;
}
} void solve_duplicate_substr(int n){
int i, j, pos, ans = ;
for(i = ; i < n; ++i){
if(h[rank[i]] > ans){
ans = h[rank[i]];
pos = i;
}
}
for(i = pos; i < pos + ans; ++i){
printf("%c", a[i]);
}
printf("\n");
} void slove_update_duplicate_substr(int n, int k){
int i, j;
int low = , high = n;
int ans = , pos1 = , pos2 = ;
while(low <= high){
int mid = (low + high) / ;
bool flag = false;
for(i = ; i < n; ++i){
if(h[i] >= mid){
++ans;
if(ans >= k) flag = true;
}
else ans = ;
}
if(flag) low = mid + ;
else high = mid - ;
}
cout << high << endl;
} int main(){
int i, j, t, n, m, k;
while(cin >> n >> k){
for(i = ; i < n; ++i) cin >> a[i];
suffix_array(a, sa, n, );
calc_height(a, sa, h, n);
slove_update_duplicate_substr(n, k);
}
return ;
}

POJ 3261 可重叠的 k 次最长重复子串【后缀数组】的更多相关文章

  1. POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)+后缀数组模板

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7586   Accepted: 3448 Cas ...

  2. 【POJ 3261】Milk Patterns 可重叠的k次最长重复子串

    可重叠的k次最长重复子串 #include<cstdio> #include<cstring> #include<algorithm> using namespac ...

  3. poj 3261 后缀数组 可重叠的 k 次最长重复子串

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 16430   Accepted: 7252 Ca ...

  4. poj 3261 求可重叠的k次最长重复子串

    题意:求可重叠的k次最长重复子串的长度 链接:点我 和poj1743差不多 #include<cstdio> #include<iostream> #include<al ...

  5. 后缀数组练习2:可重叠的k次最长重复子串

    其实和上一题是差不多的,只是在二分check的时候有一些小小的改动 1468: 后缀数组2:可重叠的k次最长重复子串 poj3261 时间限制: 1 Sec  内存限制: 128 MB提交: 113  ...

  6. poj 1743 Musical Theme(最长重复子串 后缀数组)

    poj 1743 Musical Theme(最长重复子串 后缀数组) 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复 ...

  7. 【poj1743-Musical Theme】不可重叠最长重复子串-后缀数组

    http://poj.org/problem?id=1743 这题是一道后缀数组的经典例题:求不可重叠最长重复子串. 题意: 有N(1 <= N <=20000)个音符的序列来表示一首乐曲 ...

  8. poj3261 Milk Patterns 后缀数组求可重叠的k次最长重复子串

    题目链接:http://poj.org/problem?id=3261 思路: 后缀数组的很好的一道入门题目 先利用模板求出sa数组和height数组 然后二分答案(即对于可能出现的重复长度进行二分) ...

  9. POJ 3261 Milk Patterns (后缀数组,求可重叠的k次最长重复子串)

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 16742   Accepted: 7390 Ca ...

随机推荐

  1. Python之登陆接口设计

    刚刚开始学习Python,第一个编写的程序. import os user_file = open('use_file.txt', 'r') user_list = user_file.readlin ...

  2. [LeetCode]题解(python):121-Best Time to Buy and Sell Stock

    题目来源: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ 题意分析: 给定一个数组,代表array[i] 代表第i天的价 ...

  3. [LeetCode]题解(python):097-Interleaving String

    题目来源: https://leetcode.com/problems/interleaving-string/ 题意分析: 给定字符串s1,s2,s3,判断s3是否由s1和s2穿插组成.如“abc” ...

  4. NET Core个人博客

    NET Core重写个人博客站点小结 今天用ASP.NET Core重写了个人博客站点,原来是基于ASP.NET 4.5开发的.重写工作总体很顺利,最后成功发布到Ubunt+Nginx平台上.效果如下 ...

  5. android中使用jni对字符串加解密实现分析

    android中使用jni对字符串加解密实现分析 近期项目有个需求.就是要对用户的敏感信息进行加密处理,比方用户的账户password,手机号等私密信息.在java中,就对字符串的加解密我们能够使用A ...

  6. cocos2d-x 源代码 :可以循环CCScrollView (,代码已被重构连接使用)

    cocos2d-x来源合计文件夹 http://blog.csdn.net/u011225840/article/details/31743129 1.准备工作 想弄懂可循环的CCscrollView ...

  7. uva 1561 - Cycle Game(推理)

    option=com_onlinejudge&Itemid=8&page=show_problem&problem=4336" style=""& ...

  8. c 计算Fibonacci数列:1,1,2,3,5,8,13……这题也是很经典。

    输出数字序列2/,/,/,/,/,/...,输出个数由键盘输入.注意输入使用scanf输入 比如: 输入 3输出为 / / / 输入 输出为 / / / / #include<stdio.h&g ...

  9. 利用CSS、JavaScript及Ajax实现图片预加载的三大方法(转)

    预加载图片是提高用户体验的一个很好方法.图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度.这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速.无缝地发布 ...

  10. win7如何快速设置开机启动项?

    添加开机启动项方法: 找到windows开始菜单->所有程序->启动,右键打开, 进入C:\Users\Ocean\AppData\Roaming\Microsoft\Windows\St ...