BZOJ2320 : 最多重复子串

本题就是求重复数最多的字典序最小的$runs$,如果重复数为1,那么做法显然,然后只考虑重复数大于1的情况。

从小到大枚举长度$len$,对于每个关键点$x=i\times len$,有且仅有一个长度为$len$的串经过它。

算出$x$与$x+len$的最长公共前缀$A$和最长公共后缀$B$后,贡献为$\lfloor\frac{A+B-1}{len}\rfloor+1$。

对于方案,可以暴力枚举所有可行起点,因为极大$runs$的总个数是$O(n)$的。

时间复杂度$O(n\log^2n)$。

#include<cstdio>
#include<cstring>
typedef unsigned long long ll;
const int N=100010,D=13331;
int T,n,m,i,j,k,x,y,A,B,L,ans,st,en;char a[N];ll pow[N],f[N];
inline ll hash(int l,int r){return f[r]-f[l-1]*pow[r-l+1];}
inline int min(int a,int b){return a<b?a:b;}
inline int lcp(int x,int y){
  if(a[x]!=a[y])return 0;
  int l=2,r=min(n-x,n-y)+1,mid,t=1;
  while(l<=r){
    mid=(l+r)>>1;
    if(hash(x,x+mid-1)==hash(y,y+mid-1))l=(t=mid)+1;else r=mid-1;
  }
  return t;
}
inline int lcs(int x,int y){
  int l=2,r=x,mid,t=1;
  while(l<=r){
    mid=(l+r)>>1;
    if(hash(x-mid+1,x)==hash(y-mid+1,y))l=(t=mid)+1;else r=mid-1;
  }
  return t;
}
inline void up(int x,int y){
  if(k>ans){ans=k,st=x,en=y;return;}
  int l0=en-st+1,l1=y-x+1,t=min(lcp(x,st),min(l0,l1));
  if((t<l1?a[x+t]:0)<(t<l0?a[st+t]:0))st=x,en=y;
}
int main(){
  scanf("%d",&T);
  for(pow[0]=i=1;i<N;i++)pow[i]=pow[i-1]*D;
  while(T--){
    scanf("%s",a+1);n=strlen(a+1);
    for(ans=i=st=en=1;i<=n;i++)if(a[i]<a[st])st=en=i;
    for(i=1;i<=n;i++)f[i]=f[i-1]*D+a[i];
    for(i=1;i+i<=n;i++)for(j=i;j<=n;j+=i){
      x=j+i;
      if(x>n)break;
      if(a[j]!=a[x])continue;
      A=lcp(j,x),B=lcs(j,x),k=(A+B-1)/i+1;
      if(k>=ans&&k>1)for(L=k*i,y=j-B+1;y+L<=i+j+A;y++)up(y,y+L-1);
    }
    for(i=st;i<=en;i++)putchar(a[i]);puts("");
  }
  return 0;
}

  

时间: 2024-10-10 18:25:42

BZOJ2320 : 最多重复子串的相关文章

【BZOJ2320】最多重复子串 调和级数+hash

[BZOJ2320]最多重复子串 Description 一个字符串P的重复数定义为最大的整数R,使得P可以分为R段连续且相同的子串.比方说,“ababab”的重复数为3,“ababa”的重复数为1. Your Task 对于给定的串S,找出S的一个子串K使得K的重复数最大. Input 第一行T表示数据组数 对于每组数据,一行中一个仅包含小写字母的字符串S Output 对于每组数据,在一行中输出K,如果有多个解,输出字典序最小的那一个 Sample Input 2 ccabababc daa

字符串中连续出现最多的子串 &amp; 字符串中最长重复子串

字符串中连续出现最多的子串 & 字符串中最长重复子串 字符串中连续出现最多的子串 & 字符串中最长重复子串,这两个问题都可以用后缀数组来表示,至于后缀数组可以参考编程珠玑P156:后缀数组就是定义一个数组指针,分别指向字符串中的对应位置,如下: a b c a b c a b c d e .substr[0] b c a b c a b c d e ....substr[1] c a b c a b c d e .......substr[2] a b c a b c d e ......

spoj687 后缀数组重复次数最多的连续重复子串

REPEATS - Repeats no tags 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

【poj3693-重复次数最多的连续重复子串】后缀数组

题意:给定一个串,长度<=10^5,求它重复次数最多的连续重复子串(输出字典序最小的那个). 例如ccabcabc,答案就是abcabc 一开始没想清楚,结果调了好久. 对于当前的L,i,i+1,x=s[i*L],y=s[(i+1)*L],找前找后,知道了最早能匹配到t0,最晚能匹配到t1,因为不知道当前的起始点是真正循环节的第几个点,所以我们要往前找L个点看看它们是不是真正的起始点. 细节就看代码吧: #include<cstdio> #include<cstdlib> #

【POJ 3693】Maximum repetition substring 重复次数最多的连续重复子串

后缀数组的论文里的例题,论文里的题解并没有看懂,,, 求一个重复次数最多的连续重复子串,又因为要找最靠前的,所以扫的时候记录最大的重复次数为$ans$,扫完后再后从头暴力扫到尾找重复次数为$ans$的第一个子串的开头,break输出就可以了 #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 1000

POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)

Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1. Given a

POJ 3693 Maximum repetition substring(最多重复次数的子串)

Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10461   Accepted: 3234 Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same cons

POJ 题目 3693 Maximum repetition substring(后缀数组+RMQ+枚举求最小字典序的重复次数最多的子串)

Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8067   Accepted: 2463 Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same conse

hihocoder-1419 后缀数组四&#183;重复旋律4 求连续重复次数最多的子串

对于重复次数,如果确定了重复子串的长度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 <