spoj687 REPEATS - Repeats (后缀数组+rmq)
A string s is called an (k,l)-repeat if s is obtained by concatenating k>=1 times some seed string t with length l>=1. For example, the string
s = abaabaabaaba
is a (4,3)-repeat with t = aba as its seed string. That is, the seed string t is 3 characters long, and the whole string s is obtained by repeating t 4 times.
Write a program for the following task: Your program is given a long string u consisting of characters ‘a’ and/or ‘b’ as input. Your program must find some (k,l)-repeat that occurs as substring within u with k as large as possible. For example, the input string
u = babbabaabaabaabab
contains the underlined (4,3)-repeat s starting at position 5. Since u contains no other contiguous substring with more than 4 repeats, your program must output the maximum k.
Input
In the first line of the input contains H- the number of test cases (H <= 20). H test cases follow. First line of each test cases is n - length of the input string (n <= 50000), The next n lines contain the input string, one character (either ‘a’ or ‘b’) per
line, in order.
Output
For each test cases, you should write exactly one interger k in a line - the repeat count that is maximized.
Example
Input:
1
17
b
a
b
b
a
b
a
a
b
a
a
b
a
a
b
a
b Output:
4
题意:给你一个长为n的字符串,然后让你找到重复次数最多的子串,并输出重复次数。
思路:这题想了很久,一开始看不懂罗穗蹇的思路(sigh),最后终于看懂了.我们先记重复的串的单位串为元串,先枚举重复的串的长度l(注意到重复次数为1一定是可以的,我们只要找到任意一个个字符就行,所以我们只要考虑重复次数大于等于2的情况),如果重复次数等于2,所以我们找到的子串(由多个元串组成)一定经过a[0],a[l],a[2*l],...a[k*l](k*l<n)等倍数点的相邻两个,因为如果只经过一个倍数点,那么这个子串的最大长度为2*l-1,不可能由两个长度为l的元串组成。所以我们对于每一个枚举的长度l,找到所有相邻倍数节点a[i*l]和a[(i+1)*l]向前和向后匹配的字符串的长度(这里指两个要匹配的字符串分别以a[i*l],a[(i+1)*l]为首字符),然后取最大值就行。这里向后匹配很简单,用后缀数组+rmq就行了,关键是向前匹配比较难处理。这里可以这样考虑,设a[i*l]和a[(i+1)*l]两个节点为首节点匹配的最大长度为k,如果k%l==0,那么就不用考虑向前匹配了,算出来的k/l+1就是循环次数,如果k%l!=0,那么就说明除了匹配k/l个循环节,还多出来k%l个字符串,那么如果i*l位置前l-k/l个字符为开头的后缀和(i+1)*l位置前l-k/l个字符为开头的后缀匹配的字符大于等于l-k/l,那么就说明还能多产生一个循环节,这里k/l+1要再加1.
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
#define lson th<<1
#define rson th<<1|1
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define maxn 50050
int sa[maxn],a[maxn];
int wa[maxn],wb[maxn],wv[maxn],we[maxn];
int rk[maxn],height[maxn];
int cmp(int *r,int a,int b,int l){
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void build_sa(int *r,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++)we[i]=0;
for(i=0;i<n;i++)we[x[i]=r[i]]++;
for(i=1;i<m;i++)we[i]+=we[i-1];
for(i=n-1;i>=0;i--)sa[--we[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<n;i++)wv[i]=x[y[i]];
for(i=0;i<m;i++)we[i]=0;
for(i=0;i<n;i++)we[wv[i]]++;
for(i=1;i<m;i++)we[i]+=we[i-1];
for(i=n-1;i>=0;i--)sa[--we[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
void calheight(int *r,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++)rk[sa[i]]=i;
for(i=0;i<n;height[rk[i++] ]=k){
for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
}
}
int minx[maxn][30];
void init_rmq(int n)
{
int i,j;
height[1]=inf;
for(i=1;i<=n;i++)minx[i][0]=height[i];
for(j=1;j<=16;j++){
for(i=1;i<=n;i++){
if(i+(1<<j)-1<=n){
minx[i][j]=min(minx[i][j-1],minx[i+(1<<(j-1))][j-1]);
}
}
}
}
int lcp(int l,int r)
{
int k,i;
if(l>r)swap(l,r);
l++;
k=(log((r-l+1)*1.0)/log(2.0));
return min(minx[l][k],minx[r-(1<<k)+1][k]);
}
int main()
{
int n,m,i,j,T,l,beishu,yushu,len;
scanf("%d",&T);
char s[10];
while(T--)
{
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%s",s);
a[i]=s[0]-'a'+1;
}
a[n]=0;
build_sa(a,n+1,130);
calheight(a,n);
init_rmq(n);
int ans=1;
for(l=1;l<=n;l++){
for(i=0;i+l<n;i+=l){
len=lcp(rk[i],rk[i+l] );
beishu=len/l+1;
yushu=len%l;
if(i-(l-yushu)>=0 && yushu!=0 && lcp(rk[i-(l-yushu) ],rk[i+l-(l-yushu) ])>=yushu ){
beishu++;
}
ans=max(ans,beishu);
}
}
printf("%d\n",ans);
}
return 0;
}
spoj687 REPEATS - Repeats (后缀数组+rmq)的更多相关文章
- SPOJ REPEATS Repeats (后缀数组 + RMQ:子串的最大循环节)题解
题意: 给定一个串\(s\),\(s\)必有一个最大循环节的连续子串\(ss\),问最大循环次数是多少 思路: 我们可以知道,如果一个长度为\(L\)的子串连续出现了两次及以上,那么必然会存在\(s[ ...
- 【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过
题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&am ...
- POJ 3693 后缀数组+RMQ
思路: 论文题 后缀数组&RMQ 有一些题解写得很繁 //By SiriusRen #include <cmath> #include <cstdio> #includ ...
- 【SPOJ – REPEATS】 后缀数组【连续重复子串】
字体颜色如何 字体颜色 SPOJ - REPEATS 题意 给出一个字符串,求重复次数最多的连续重复子串. 题解 引自论文-后缀数组--处理字符串的有力工具. 解释参考博客 "S肯定包括了字 ...
- SPOJ 687 Repeats(后缀数组+ST表)
[题目链接] http://www.spoj.com/problems/REPEATS/en/ [题目大意] 求重复次数最多的连续重复子串的长度. [题解] 考虑错位匹配,设重复部分长度为l,记s[i ...
- SPOJ Repeats(后缀数组+RMQ-ST)
REPEATS - Repeats no tags A string s is called an (k,l)-repeat if s is obtained by concatenating k& ...
- HDU2459 后缀数组+RMQ
题目大意: 在原串中找到一个拥有连续相同子串最多的那个子串 比如dababababc中的abababab有4个连续的ab,是最多的 如果有同样多的输出字典序最小的那个 这里用后缀数组解决问题: 枚举连 ...
- hdu 2459 (后缀数组+RMQ)
题意:让你求一个串中连续重复次数最多的串(不重叠),如果重复的次数一样多的话就输出字典序小的那一串. 分析:有一道比这个简单一些的题spoj 687, 假设一个长度为l的子串重复出现两次,那么它必然会 ...
- ural 1297(后缀数组+RMQ)
题意:就是让你求一个字符串中的最长回文,如果有多个长度相等的最长回文,那就输出第一个最长回文. 思路:这是后缀数组的一种常见的应用,首先把原始字符串倒转过来,然后接在原始字符串的后面,中间用一个不可能 ...
随机推荐
- 深入剖析setState同步异步机制
关于 setState setState 的更新是同步还是异步,一直是人们津津乐道的话题.不过,实际上如果我们需要用到更新后的状态值,并不需要强依赖其同步/异步更新机制.在类组件中,我们可以通过thi ...
- MySQL select 语句指定字段查询
指定字段查询 SELECT 语法 SELECT [ALL | DISTINCT] {* | table.* | [table.field1[as alias1][,table.field2[as al ...
- k8s集群中遇到etcd集群故障的排查思路
一次在k8s集群中创建实例发现etcd集群状态出现连接失败状况,导致创建实例失败.于是排查了一下原因. 问题来源 下面是etcd集群健康状态: 1 2 3 4 5 6 7 8 9 10 11 [roo ...
- SAP IDES登陆的short dump终于不见了
还记得这个IDES登陆的shortdump吗今天对内核从701_rel 升级到721,发现登陆的错误没了,看来721_rel内核支持的操作系统和数据库更多了,兼容性也更好了.
- SAP中数据库表长度的界定
SAP中,如何查看表和关键字的长度?通过SE11菜单栏Extras->table width 可以看到.然而SAP在系统也会将表分类,特别是在可扩展的表维护视图中,分为如下几类 ult ...
- Nginx的简介和使用nginx实现请求转发
一.什么是Nginx Nginx是lgor Sysoev为俄罗斯访问量第二的rambler.ru站点设计开发的.从2004年发布至今,凭借开源的力量,已经接近成熟与完善. Nginx功能丰富,可作为H ...
- Socket.IO基础教程
什么是Socket.IO Socket.IO是一个库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信.它包括: 使Node.js服务器:来源 | API 为浏览器(可从Node.js的也运行 ...
- 前端面试之JavaScript中this的指向【待完善!】
JavaScript中this的指向问题! 另一个特殊的对象是 this,它在标准函数和箭头函数中有不同的行为. 在标准函数中, this 引用的是把函数当成方法调用的上下文对象,这时候通常称其为 t ...
- 提取一个int类型数最右侧的1
提取一个int类型数最右侧的1 算法描述 把一个int类型的数,提取出最右侧的1来,例如: 6 对应的二进制位 0000 0110,那么取出来的应该是0000 0010 算法思路 对原数0000 01 ...
- VS2019中scanf返回值被忽略的问题及其解决方法
目录 [问题](#昨天在使用Visual Studio 2019编写C语言程序时遇到了scanf返回值被忽略问题) 问题原因 方法① 方法② 方法③ 方法④ 昨天在使用Visual Studio 20 ...