首页 > 代码库 > bzoj2320: 最多重复子串

bzoj2320: 最多重复子串

2320: 最多重复子串

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 246  Solved: 66
[Submit][Status][Discuss]

Description

一个字符串P的重复数定义为最大的整数R,使得P可以分为R段连续且相同的子串。比方说,“ababab”的重复数为3,“ababa”的重复数为1。

Your Task

对于给定的串S,找出S的一个子串K使得K的重复数最大。

 

Input

第一行T表示数据组数

对于每组数据,一行中一个仅包含小写字母的字符串S

 

Output

对于每组数据,在一行中输出K,如果有多个解,输出字典序最小的那一个

 

Sample Input

2
ccabababc
daabbccaa

Sample Output


ababab
aa

HINT

 

100%:T≤10,S的长度不超过100000

 

题解

……我就来贴个代码吧……orz下claris……

技术分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 typedef unsigned long long ll;
 5 const int N=100010,base=127;
 6 int ans,k,st,ed,n,m,time,i,l;char s[N];ll f[N],pow[N];
 7 using namespace std;
 8 ll hash(int l,int r){return f[r]-f[l-1]*pow[r-l+1];}
 9 int lcs(int x,int y)
10 {
11     int l=0,r=min(x,y);
12     while(l<r){
13         int mid=(l+r)/2;
14         if(hash(x-mid,x)==hash(y-mid,y))l=mid+1;else r=mid;
15     }
16     return l;
17 }
18 int lcp(int x,int y)
19 {
20     int l=0,r=min(n-x+1,n-y+1);
21     while(l<r){
22         int mid=(l+r)/2;
23         int a=hash(x,x+mid);
24         int b=hash(y,y+mid);
25         if(hash(x,x+mid)==hash(y,y+mid))l=mid+1;else r=mid;
26     }
27     return l;
28 }
29 void up(int x,int y)
30 {
31     if(k>ans){ans=k;st=x;ed=y;return;}
32     int l0=ed-st+1,l1=y-x+1,t=lcp(x,st);
33     if(t==min(l0,l1)){
34         if(t==l0)return;
35         st=x;ed=y;return;
36     }
37     if(s[st+t]>s[x+t]){st=x;ed=y;}
38 }
39 int main()
40 {
41     scanf("%d",&time);
42     for(i=1,pow[0]=1;i<=N;i++)pow[i]=pow[i-1]*base;
43     while(time--)
44     {
45         scanf("%s",s+1);n=strlen(s+1);
46         for(ans=st=ed=i=1;i<=n;i++)
47             if(s[i]<s[st])st=ed=i;
48         for(f[0]=0,i=1;i<=n;i++)f[i]=f[i-1]*base+s[i];
49         for(int i=1;i<=n/2;i++)
50             for(int j=1;j<=n;j+=i){
51                 int x=j+i;if(x>n)break;
52                 if(s[j]!=s[x])continue;
53                 int a=lcp(j,x),b=lcs(j,x);
54                 k=(a+b-1)/i+1;
55                 l=k*i;
56                 if(k>=ans)for(int y=j-b+1;y<=i+j+a-l;y++)up(y,y+l-1);
57             }
58         for(int i=st;i<=ed;i++)putchar(s[i]);puts("");
59     }
60     return 0;
61 }
View Code

 

bzoj2320: 最多重复子串