对于重复次数,如果确定了重复子串的长度len,那重复次数k=lcp(start,start+len)/len+1。而暴力枚举start和len的复杂度是O(n^2),不能接受。而有一个规律,若我们只枚举len的整数倍作为起始,如果将它向前移动小于len位可以构成重复次数更长的串,那么那个位置p=start-len+lcp%len。所以每次我们计算两者并求max再与ans做max即可。

#include <cstdio>
#include <string>
#include <iostream>
#include <set>
#include <algorithm>
#include <vector>
#include <map>
#include <cstring>
#include <queue>
#define LL int
using namespace std;
const LL N = ; class SF
{
//N:数组大小
public:
int x[N], y[N], c[N];
int Height[N], str[N], SA[N], Rank[N];//Height数组从2开始,SA记录Rank=i的下标
int slen;
int m = ;//字符集处理大小(传入如果不是数字,需要做位移转换)
bool cmp(int* r, int a, int b, int l) {
return r[a] == r[b] && r[a + l] == r[b + l];
}
void Suffix(int n) {
++n;
int i, j, p;
for (i = ; i < m; ++i) c[i] = ;
for (i = ; i < n; ++i) c[x[i] = str[i]]++;
for (i = ; i < m; ++i) c[i] += c[i - ];
for (i = n - ; i >= ; --i) SA[--c[x[i]]] = i;
for (j = ; j <= n; j <<= ) {
p = ;
for (i = n - j; i < n; ++i) y[p++] = i;
for (i = ; i < n; ++i) if (SA[i] >= j) y[p++] = SA[i] - j;
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]] = cmp(y, SA[i - ], SA[i], j) ? p - : p++;
}
if (p >= n)break;
m = p;
} int k = ;
n--;
for (i = ; i <= n; ++i) Rank[SA[i]] = i;
for (i = ; i < n; ++i) {
if (k)--k;
j = SA[Rank[i] - ];
while (str[i + k] == str[j + k])++k;
Height[Rank[i]] = k;
//cout << k << endl;
}
}
static const int bitlen = ;
LL lg2(LL p)//计算log2(n)
{
return (LL)(log(p) / log());
}
LL dp[bitlen][N];
LL bit[bitlen];
void initRMQ()//初始化
{
bit[] = ;
for (int i = ; i < bitlen; i++) bit[i] = * bit[i - ];
for (int i = ; i <= slen; i++)
dp[][i] = Height[i];
dp[][] = dp[][] = ;
for (LL i = ; bit[i] < slen + ; i++)
for (LL j = ; j + bit[i] <= slen + ; j++)
dp[i][j] = min(dp[i - ][j], dp[i - ][j + bit[i - ]]);
}
LL query(LL l, LL r)//查询两个Rank之间的lcp
{
if (r == l) return slen - SA[l];
if (l > r) swap(l, r);
l++;
LL mig = lg2(r - l + 1.0);
return min(dp[mig][l], dp[mig][r - bit[mig] + ]);
}
void init(string &s)
{
slen = s.size();
for (int i = ; i < slen; i++)
str[i] = s[i] - 'a' + ;//如果是字符,映射成从1开始的序列
str[slen] = ;//1作为结束符,防止越界
Suffix(slen);
initRMQ();
}
int solve()
{
int ans = ;
for (int len = ; len <= slen; len++)
{
for (int i = ; i+len < slen; i+=len)
{
int r1 = Rank[i], r2 = Rank[i+ len];
int lcp = query(r1, r2);
ans = max(ans, lcp / len + );
if (i - len + lcp%len >= )
{
lcp = query(Rank[i - len + lcp%len], Rank[i + lcp%len]);
ans = max(ans, lcp / len + );
}
}
}
return ans;
}
}sf;
int main()
{
cin.sync_with_stdio(false);
string s;
while (cin >> s)
{
sf.init(s);
cout << sf.solve() << endl;
}
return ;
}

hihocoder-1419 后缀数组四·重复旋律4 求连续重复次数最多的子串的更多相关文章

  1. hihocoder #1419 : 后缀数组四·重复旋律4

    #1419 : 后缀数组四·重复旋律4 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构 ...

  2. hiho一下123周 后缀数组四·重复旋律

    后缀数组四·重复旋律4 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列.小Hi ...

  3. hihoCoder 1403 后缀数组一·重复旋律(后缀数组+单调队列)

    #1403 : 后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成 ...

  4. hihocoder 1457 后缀自动机四·重复旋律7 求不同子串的和

    描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的是小Hi发现了一部名字叫<十进制进行曲大全>的作品集,顾名思义,这部作品集里有许多作品 ...

  5. hihocoder #1415 : 后缀数组三·重复旋律3

    #1415 : 后缀数组三·重复旋律3 Time Limit:5000ms Case Time Limit:1000ms Memory Limit:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢 ...

  6. hihocoder #1407 : 后缀数组二·重复旋律2

    #1407 : 后缀数组二·重复旋律2 Time Limit:5000ms Case Time Limit:1000ms Memory Limit:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢 ...

  7. HIHOcoder 1403 后缀数组一·重复旋律

    思路 后缀数组的板子题,注意后缀数组的rank[]数组是通过位置找到对应排名的,sa[]是通过排名找到位置的,height[i]记录的是sa[i]和sa[i+1]之间的lcp 不要写错了就行了 代码 ...

  8. hihoCoder 1403 后缀数组 重复旋律

    思路: 后缀数组 第一次写 留个模板吧 先求出后缀数组,问题转换为询问height数组中连续k-1个数的最小值的最大值,单调队列扫描一遍即可.-yousiki 手懒用得STL //By SiriusR ...

  9. hihocoder 后缀自动机五·重复旋律8 求循环同构串出现的次数

    描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 小Hi发现旋律可以循环,每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以 ...

随机推荐

  1. ol3对地图上某些特定的经纬度进行标注

    最终效果需要类似于这种 1.首先我们需要一个最基本的地图,这一步骤可以浏览该分类下的上一篇随笔. 2.ol3支持的文件格式有.geojson,我们需要将坐标制作成符合这种格式的样子才能被ol3识别并显 ...

  2. hdfoo站点开发笔记

    为了安全,也要兼顾编辑器切换管理 开发时不必管目录名称的事, 只是在部署的时候,才修改应用目录和tp目录的名字就行了. 为了提高tp的加载效率, 始终给app和tp以绝对路径.就是以 realpath ...

  3. word如何替换行首?

    在替换窗口, 要使用通配符 要使用 替换中的 分组, 高级替换 表示行首的符号, 使用 (<*) 表示 单词开始的位置, 使用 <, 表示单词结束的位置, 使用 > 替换的示例:

  4. P1552 [APIO2012]派遣

    链接 https://www.luogu.org/problemnew/show/P1552 思路 忍者数量肯定越多越好 那就从下到上的合并它的孩子 左偏树的话 顺便维护一个tot,大头堆,如果tot ...

  5. SpringBoot Redis使用fastjson进行序列化

    在使用spring-data-redis,默认情况下是使用org.springframework.data.redis.serializer.JdkSerializationRedisSerializ ...

  6. Python SSH爆破以及Python3线程池控制线程数

    源自一个朋友的要求,他的要求是只爆破一个ip,结果出来后就停止,如果是爆破多个,完全没必要停止,等他跑完就好 #!usr/bin/env python #!coding=utf-8 __author_ ...

  7. jvm 内存溢出问题排查方法

    如果你做TCP通讯或者map集合操作,并发处理等功能时,很容易出现 Java 内存溢出的问题.本篇文章,带领大家深入jvm,分析并找出jvm内存溢出的代码. jvm中除了程序计数器,其他的区域都有可能 ...

  8. ISE14.7兼容性问题集锦https://www.cnblogs.com/ninghechuan/p/7241371.html

    ISE14.7兼容性问题集锦 对于电子工程师来说,很多电路设计仿真软件都是特别大的,安装下来一般都是上G,甚至几十G,而且win7的兼容性也是最好的,不愿意升级win10是因为麻烦,而且没有必要,对于 ...

  9. JavaScript——执行环境、变量对象、作用域链

    前言 这几天在看<javascript高级程序设计>,看到执行环境和作用域链的时候,就有些模糊了.书中还是讲的不够具体.通过上网查资料,特来总结,以备回顾和修正. 目录: EC(执行环境或 ...

  10. Linux命令去重统计排序

    利用Linux命令进行文本按行去重并按重复次数排序   linux命令行提供了非常强大的文本处理功能,组合利用linux命令能实现好多强大的功能.本文这里举例说明如何利用Linux命令行进行文本按行去 ...