Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 5946   Accepted: 1799

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 string containing lowercase letters, you are to find a substring of it with maximum repetition number.

Input

The input consists of multiple test cases. Each test case contains exactly one line, which
gives a non-empty string consisting of lowercase letters. The length of the string will not be greater than 100,000.

The last test case is followed by a line containing a '#'.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by the substring of maximum repetition number. If there are multiple substrings of maximum repetition number, print the lexicographically smallest one.

Sample Input

ccabababc
daabbccaa
#

Sample Output

Case 1: ababab
Case 2: aa
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef long long LL;
using namespace std; const int MAX=100000+10;
int *rank,r[MAX],sa[MAX],height[MAX],L[MAX];
int wa[MAX],wb[MAX],wm[MAX],f[MAX][32];
char s[MAX]; bool cmp(int *r,int a,int b,int l){
return r[a] == r[b] && r[a+l] == r[b+l];
} void makesa(int *r,int *sa,int n,int m){
int *x=wa,*y=wb,*t;
for(int i=0;i<m;++i)wm[i]=0;
for(int i=0;i<n;++i)wm[x[i]=r[i]]++;
for(int i=1;i<m;++i)wm[i]+=wm[i-1];
for(int i=n-1;i>=0;--i)sa[--wm[x[i]]]=i;
for(int i=0,j=1,p=0;p<n;j=j*2,m=p){//j表示合并的子串长度
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<m;++i)wm[i]=0;
for(i=0;i<n;++i)wm[x[y[i]]]++;
for(i=1;i<m;++i)wm[i]+=wm[i-1];
for(i=n-1;i>=0;--i)sa[--wm[x[y[i]]]]=y[i];
for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;++i){//求新的x,相当于rank,但是相同的子串要排名相同
x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;//判断子串suffix(sa[i])与suffix(sa[i-1])是否相同并且确定排名
}
}
rank=x;
} /*在计算好height[rank[i]]后,对于height[rank[i+1]],如果sa[rank[i]-1]的首字母和sa[rank[i]]首字母相同
则rank[i+1]肯定在rank[sa[rank[i]-1]+1]后面,根据排名为a,b的子串的最长公共前缀为[a,b]中最小的
所以i+1和sa[rank[i+1]-1]的公共前缀>=height[rank[i]]-1即>=k-1;
如果sa[rank[i]-1]的首字母和sa[rank[i]]首字母不相同,则上一次的k就是0,所以无影响
*/
void calheight(int *r,int *sa,int n){
for(int i=0,j=0,k=0;i<n;height[rank[i++]]=k){
for(k?--k:0,j=sa[rank[i]-1];r[i+k] == r[j+k];++k);
}
} void InitRMQ(int n){
for(int i=1;i<=n;++i)f[i][0]=height[i];//初始化从i开始区间长度为2^0的最值
int l=log(n*1.0)/log(2.0);//2*l<=n
for(int j=1;j<=l;++j){
for(int i=1;i+(1<<j)-1<=n;++i){//i+2^j-1<=n
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);//i+2^j-1 - (i+2^(j-1))+1=2^(j-1)
}
}
} int LCP(int i,int j){//求rank[i]与rank[i]+1,ran[i]+1与rank[i]+2...的最长公共前缀中的最值,即height[rank[i]+1]~height[rank[j]]的最值
i=rank[i],j=rank[j];
if(i>j)swap(i,j);
++i;
int l=log(j-i+1.0)/log(2.0);//2^l<=j-i+1
return min(f[i][l],f[j-(1<<l)+1][l]);
} int main(){
int Case=0;
while(scanf("%s",s),s[0] != '#'){
int n=0;
for(n=0;s[n] != '\0';++n)r[n]=s[n];
r[n]=0;
makesa(r,sa,n+1,256);
calheight(r,sa,n);
InitRMQ(n);
int sum=0,size=0,x=sa[1],y=sa[1]+1;
for(int j=1;j<=n;++j){//对于长度为j的循环节,sum记录循环次数
for(int i=0;i+j<n;i+=j){
if(s[i] == s[i+j]){
int len=LCP(i,i+j);//向后匹配
int num=len/j;
int k=i-(j-len%j);
if(k>=0 && len%j && LCP(k,k+j)>=len)++num;//向前匹配
if(num == sum)L[++size]=j;//L记录得到最多循环次数的可能的子串长度
else if(num > sum)sum=num,L[size=0]=j;
}
}
}
for(int i=1;i<=n && sum;++i){//求哪个子串可以循环sum次
for(int j=0;j<=size;++j){
if(sa[i]+L[j]>=n)continue;
int len=LCP(sa[i],sa[i]+L[j]);
if(len/L[j] == sum){x=sa[i],y=sa[i]+(sum+1)*L[j],sum=0;break;}
}
}
printf("Case %d: ",++Case);
for(int i=x;i<y;++i)printf("%c",s[i]);
printf("\n");
}
return 0;
}

poj3693之后缀数组的更多相关文章

  1. poj3693(后缀数组)

    poj3693 题意 给出一个串,求重复次数最多的连续重复子串,输出字典序最小的. 分析 论文 例8(P21). Sparse-Table算法预处理出任意两个后缀串的LCP. code #includ ...

  2. POJ3693(SummerTrainingDay10-J 后缀数组)

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10241   Ac ...

  3. 【poj3693】Maximum repetition substring(后缀数组+RMQ)

    题意:给定一个字符串,求重复次数最多的连续重复子串. 传说中的后缀数组神题,蒟蒻真的调了很久才对啊.感觉对后缀数组和RMQ的模版都不是很熟,导致还是会有很多各种各样的小错误= = 首先,枚举重复子串的 ...

  4. POJ3693 Maximum repetition substring [后缀数组 ST表]

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9458   Acc ...

  5. POJ3693 Maximum repetition substring 后缀数组

    POJ - 3693 Maximum repetition substring 题意 输入一个串,求重复次数最多的连续重复字串,如果有次数相同的,则输出字典序最小的 Sample input ccab ...

  6. 关于后缀数组的倍增算法和height数组

    自己看着大牛的论文学了一下后缀数组,看了好久好久,想了好久好久才懂了一点点皮毛TAT 然后就去刷传说中的后缀数组神题,poj3693是进化版的,需要那个相同情况下字典序最小,搞这个搞了超久的说. 先简 ...

  7. 【UVA10829】 L-Gap Substrings (后缀数组)

    Description If a string is in the form UVU, where U is not empty, and V has exactly L characters, we ...

  8. 【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过

    题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&am ...

  9. 【距离GDOI:131天】 后缀数组完毕

    用了近两周的时间,终于把罗神那篇后缀数组应用看完了,题目也写了一遍,T了无数次...详见前几篇博文... 后缀数组很重要的是那个height数组,可以用来做各种奇奇怪怪的东西...常用方法去是去二分, ...

随机推荐

  1. rsyslog 传输日志

    nginx 服务器: front-end:/usr/local/nginx/logs# cat /etc/rsyslog.conf | grep -v "^$" | grep -v ...

  2. android下tcpdump抓包

    tcpdump是最快捷方便的抓包方式,还可以加深对网络协议的理解.android下可以通过如下方式抓包: 1 Android上启动tcpdump Android设备可以把tcpdump的可执行文件上传 ...

  3. clistctrl 虚拟列表

    一.什么是虚拟列表控件 虚拟列表控件是指带有LVS_OWNERDATA风格的列表控件.. 二.为什么使用虚拟列表控件 我们知道,通常使用列表控件CListCtrl,需要调用InsertItem把要显示 ...

  4. kbengine简单介绍(1)

    什么是kbengine? 一款开源的游戏服务端引擎,客户端通过简单的约定协议就能与服务端通讯, 使用KBEngine插件能够快速与(Unity3D, OGRE, Cocos2d-x, HTML5, 等 ...

  5. 《网络编程》Unix 域套接字

    概述 Unix 域套接字是一种client和server在单主机上的 IPC 方法.Unix 域套接字不运行协议处理,不须要加入或删除网络报头,无需验证和,不产生顺序号,无需发送确认报文,比因特网域套 ...

  6. POJ 2115 模线性方程 ax=b(mod n)

    /* (x*c+a)%(2^k)==b →(x*c)%(2^k)==b-a 满足定理: 推论1:方程ax=b(mod n)对于未知量x有解,当且仅当gcd(a,n) | b. 推论2:方程ax=b(m ...

  7. C++中引用

    在C语言中&这个符号表示了取地址符,但是在C++中它却有着不同的用途,掌握C++的&符号,是提高代码执行效率和增强代码质量的一个很好的办法.一.引用简介 引用就是某一变量(目标)的一个 ...

  8. Construct Binary Tree From Inorder and Preorder/Postorder Traversal

    map<int, int> mapIndex; void mapToIndex(int inorder[], int n) { ; i < n; i++) { mapIndex.in ...

  9. BZOJ 1266: [AHOI2006]上学路线route(最短路+最小割)

    第一问最短路.第二问,先把最短路的图建出来(边(u,v)满足d[s->u]+d[v->t]+d(u,v)==最短路径长度,就在图中,可以从源点和汇点分别跑一次最短路得到每个点到源点和汇点的 ...

  10. python初探-copy

    python中,数据的拷贝有以下三种形式:赋值.浅copy和深copy.根据类型的不同,可以把数据分成以下两类:字符串和数字为一类,其他(包括列表.元祖.字典...)为一类. 在python中有池的概 ...