题目大意

给出一个数字串,找出其中至少重复K次的最长的子串长度。

题目分析

直接用后缀数组来求解,限制height[i]的长度来对排好序的后缀进行分组(这种方法经常在字符串问题中被使用)。 
    先判断是否有至少K个长度大于等于M的子串,这可以通过将height[i] >= M来对排好序的后缀进行分组,然后判断组内串的个数是否大于等于K来实现。 
    然后,用二分法得到最大的M。

实现(c++)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#define LETTERS 1000005
#define MAX_ARRAY_SIZE 1000005
int gSuffixArray[MAX_ARRAY_SIZE];
int gCount[MAX_ARRAY_SIZE];
int gOrderBySecondKey[MAX_ARRAY_SIZE];
int gRank[MAX_ARRAY_SIZE];
int gFirstKeyArray[MAX_ARRAY_SIZE];
int gHeight[MAX_ARRAY_SIZE]; int gStr[MAX_ARRAY_SIZE];
int gStrLen; bool Compare(int* arr, int a, int b, int step){
return arr[a] == arr[b] && arr[a + step] == arr[b + step];
} void GetStr(char* str){
memset(gStr, 0, sizeof(gStr));
gStrLen = strlen(str);
for (int i = 0; i < gStrLen; i++){
gStr[i] = str[i] - 'a' + 1;
}
gStr[gStrLen] = 0;
gStrLen++;
}
//求后缀数组
void GetSuffixArray(){
int n = gStrLen;
memset(gCount, 0, sizeof(gCount));
for (int i = 0; i < n; i++){
gRank[i] = gStr[i];
gCount[gRank[i]] ++;
}
int m = LETTERS;
for (int i = 1; i < m; i++){
gCount[i] += gCount[i - 1];
}
for (int i = n - 1; i >= 0; i--){
gSuffixArray[--gCount[gRank[i]]] = i;
} int step = 1;
int *rank = gRank, *order_by_second_key = gOrderBySecondKey;
while (step < n){
int p = 0; for (int i = n - step; i < n; i++){
order_by_second_key[p++] = i;
}
for (int i = 0; i < n; i++){
if (gSuffixArray[i] >= step){
order_by_second_key[p++] = gSuffixArray[i] - step;
}
}
for (int i = 0; i < n; i++){
gFirstKeyArray[i] = rank[order_by_second_key[i]];
}
for (int i = 0; i < m; i++){
gCount[i] = 0;
}
for (int i = 0; i < n; i++){
gCount[gFirstKeyArray[i]] ++;
}
for (int i = 1; i < m; i++){
gCount[i] += gCount[i - 1];
}
for (int i = n - 1; i >= 0; i--){
gSuffixArray[--gCount[gFirstKeyArray[i]]] = order_by_second_key[i];
}
int* tmp = rank; rank = order_by_second_key; order_by_second_key = tmp;
rank[gSuffixArray[0]] = p = 0;
for (int i = 1; i < n; i++){
if (Compare(order_by_second_key, gSuffixArray[i], gSuffixArray[i - 1], step)){
rank[gSuffixArray[i]] = p;
}
else{
rank[gSuffixArray[i]] = ++p;
}
}
m = p + 1;
step *= 2;
}
}
//求height数组
void GetHeight(){
int n = gStrLen;
for (int i = 0; i < n; i++){
gRank[gSuffixArray[i]] = i;
}
int k = 0, j;
for (int i = 0; i < n; i++){
if (k){
k--;
}
j = gSuffixArray[gRank[i] - 1];
while (j + k < n && i + k < n&& gStr[i + k] == gStr[j + k]){
k++;
}
gHeight[gRank[i]] = k;
}
} bool Find(int k, int len){
int end = 1;
int count = 0;
while (end < gStrLen){
count = 1;
while (end < gStrLen && gHeight[end] >= len){
count++;
end++;
}
if (count >= k){
return true;
}
end++;
}
return false;
} int main(){
int n, k;
scanf("%d %d", &n, &k); for (int i = 0; i < n; i++){
scanf("%d", &gStr[i]); gStr[i]++;
}
gStr[n] = 0;
gStrLen = n + 1;
if (k == 1){
printf("%d\n", n);
return 0;
} GetSuffixArray();
GetHeight();
int beg = 0, end = n;
while (beg < end){
int mid = (beg + end) / 2;
if (Find(k, mid)){
beg = mid + 1;
}
else{
end = mid;
}
}
printf("%d\n", beg-1);
return 0;
}

poj_3261 后缀数组的更多相关文章

  1. 后缀数组的倍增算法(Prefix Doubling)

    后缀数组的倍增算法(Prefix Doubling) 文本内容除特殊注明外,均在知识共享署名-非商业性使用-相同方式共享 3.0协议下提供,附加条款亦可能应用. 最近在自学习BWT算法(Burrows ...

  2. BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]

    4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...

  3. BZOJ 1692: [Usaco2007 Dec]队列变换 [后缀数组 贪心]

    1692: [Usaco2007 Dec]队列变换 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1383  Solved: 582[Submit][St ...

  4. POJ3693 Maximum repetition substring [后缀数组 ST表]

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

  5. POJ1743 Musical Theme [后缀数组]

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 27539   Accepted: 9290 De ...

  6. 后缀数组(suffix array)详解

    写在前面 在字符串处理当中,后缀树和后缀数组都是非常有力的工具. 其中后缀树大家了解得比较多,关于后缀数组则很少见于国内的资料. 其实后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现, ...

  7. 【UOJ #35】后缀排序 后缀数组模板

    http://uoj.ac/problem/35 以前做后缀数组的题直接粘模板...现在重新写一下模板 注意用来基数排序的数组一定要开到N. #include<cstdio> #inclu ...

  8. 【BZOJ-2119】股市的预测 后缀数组

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 334  Solved: 154[Submit][Status][Discuss ...

  9. 【BZOJ-4698】Sandy的卡片 后缀数组

    4698: Sdoi2008 Sandy的卡片 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 140  Solved: 55[Submit][Stat ...

随机推荐

  1. draw sin

    draw sin Steps 导入包 生成X轴,Y轴的数据点 设置输出图大小,像素,前景色 指定线宽,线型,绘制曲线 设置坐标轴范围 显示图形. Code #!/usr/bin/env python ...

  2. 分别通过【buildpath】和【lib】倒入JAR包有什么不同

    我们可以通过java虚拟机的类加载器来理解.通过buildpath设置(或添加)程序使用jar包的classpath.Java虚拟机是根据Java ClassLoader(类加载器)决定如何,到那里去 ...

  3. contiki rpl

    Linking target: udp-client-temperature.stk3700arm-none-eabi-gcc -Xlinker -Map=udp-client-temperature ...

  4. u-boot源码分析

    Uboot源码分析 源码以u-boot-1.3.4为基准,主芯片采用at91sam9260,主要介绍uboot执行流程. uboot官网:http://www.denx.de/wiki/U-Boot/ ...

  5. [Django学习]上传图片

    上传图片 当Django在处理文件上传的时候,文件数据被保存在request.FILES FILES中的每个键为<input type="file" name="& ...

  6. Entity Framework管理实体关系(一):管理一对一关系

    我们现在已经知道如何使用Code First来定义简单的领域类,并且如何使用DbContext类来执行数据库操作.现在我们来看下数据库理论中的多样性关系,我们会使用Code First来实现下面的几种 ...

  7. RTMP流媒体播放过程:握手,建立连接,建立流,播放

    本文讲述从打开一个RTMP流媒体到视音频数据开始播放的整个过程. 播放一个流媒体有两个前提步骤: 第一步,建立一个网络连接(NetConnection): 第二步,建立一个网络流(NetStream) ...

  8. 【转】Microsoft .Net Remoting之Marshal、Disconnect与生命周期以及跟踪服务

    Marshal.Disconnect与生命周期以及跟踪服务 一.远程对象的激活 在Remoting中有三种激活方式,一般的实现是通过RemotingServices类的静态方法来完成.工作过程事实上是 ...

  9. c# winform 自动关闭messagebox 模拟回车

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  10. ti的硬件时钟和系统时钟同步

    1.hwclock -w软到硬 hwclock -s 硬到软 2. 通过ntp网络时钟控制同步 3.etc下的localtime文件和GMT-8