题目大意

给出一个数字串,找出其中至少重复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. 设计和开发ETL系统(一)——ETL过程综述

    在这部分将按照设计和实现ETL系统的流程展开,将上一个部分的那些子系统按照提取数据.清洗和一致化.向呈现服务器提交以及管理ETL环境等四个方面进行了分类.(是不是说对ETL主要就是掌握这四个方面的内容 ...

  2. [4G]常用AT指令

    The GPRS communication module is controlled by terminal (e.g. H50) firmware. The actions are mapped ...

  3. Spring事务处理时自我调用的解决方案 嵌套AOP

    开涛的解决方案1 http://jinnianshilongnian.iteye.com/blog/1487235 AopContext.currentProxy() 原理 http://books. ...

  4. Fiddler2 java代码拦截设置

    jre -DproxySet=true -Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=8888 Or: jre -DproxySet=true -Dproxy ...

  5. div绝对定位针对手机浏览器的区别

    最近在对ipad和安卓平板做测试,发现我自己写的一个下拉控件在安卓浏览器里面被遮盖了,但是PC或者ipad都没有这个现象,一开始以为是z-index 可是无论我调多少都没有用,研究了好久,发现是代码的 ...

  6. if no 和 if not

    x = None if x is not None: print("kong") if not x is not None: print("kong") # i ...

  7. java-数据库连接工具类 DataSourceUtil.java

    DataSourceUtil.java package com.gordon.utils; import java.sql.Connection; import java.sql.ResultSet; ...

  8. 页面装载js及性能分析方法

    一.装载 先装载静态页面的引用js文件,然后查找引用文件中是否包含onload函数,比如main.js中包含onload函数,在main.js中查找是否有对其他js文件的引用,优先装载引用js文件,被 ...

  9. [mysql] MySQL Order By Rand()效率【转载】

    最近由于需要大概研究了一下MYSQL的随机抽取实现方法.举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RA ...

  10. 关于Cocos2d-x中掉帧导致游戏一卡一卡的网上一些的解决方法

    方法1 掉帧主要是setpostion引起的  因为每一帧每一个精灵都要set一次虽然不知道为什么会这样但是if(poX<1000&&pox>-100){     xx-& ...