题意:

给定一个字符串 求重复次数最多的连续重复子串 并输出字典序最小方案

题解:

枚举子串长度L 显然如果重复次数>1 那么答案串肯定包含s[1],s[1+L],s[1+L*2],...中的两个

枚举被答案包含位置 1+L*i

将1+L*i和1+L*(i+1) 向前、向后匹配 记匹配距离和为k 则重复次数为k/L

这样我们就能知道最多重复次数ans是多少

但是这题还要求字典序最小方案

求方案需要再进行一次枚举 方法同上

当重复次数和答案相等时 更新方案

但是我们知道 包含1+L*i 重复次数为k/L 的方案可能有L种 这样总时间就可能达到O(n^2)

因为这L种方案的下标是连续的 并且他们的长度相等

我们可以用线段树维护下标为x到y的rank最小值位置在哪 即可log(n)完成一个询问

总复杂度O(nlog^2(n))

(但是好像常数写好一点不用线段树也能过- - 我就没加跑得比AK加了还快。。)

代码:

 #include <cstdio>
#include <cstring>
const int N=;
int n,ans,ansx,ansy,x[N],y[N],sa[N],rank[N],hi[N],ws[N],a[N],lon,min[N][];
char s[N];
void sort(int t){
for (int i=;i<=n;i++) ++ws[x[y[i]]];
for (int i=;i<=t;i++) ws[i]+=ws[i-];
for (int i=n;i;i--) sa[ws[x[y[i]]]--]=y[i];
for (int i=;i<=t;i++) ws[i]=;
}
bool check(int a,int b,int c){ return y[a]==y[b] && y[a+c]==y[b+c]; }
void makesa(){
int p=,tt=;
for (int i=;i<=n;i++) x[i]=a[i],y[i]=i;
sort(tt);
for (int j=;j<=n;j<<=,tt=p,p=){
for (int i=n-j+;i<=n;i++) y[++p]=i;
for (int i=;i<=n;i++)
if (sa[i]>j) y[++p]=sa[i]-j;
sort(tt);
for (int i=;i<=n;i++) y[i]=x[i];
x[sa[]]=p=;
for (int i=;i<=n;i++)
x[sa[i]]=check(sa[i],sa[i-],j) ? p : ++p;
}
}
void makehi(){
for (int i=;i<=n;i++) rank[sa[i]]=i;
for (int i=,k=;i<=n;hi[rank[i++]]=k)
if (rank[i]==) k=;
else for (k=k ? k- : k;a[i+k]==a[sa[rank[i]-]+k];++k);
}
int minn(int x,int y){ return x<y ? x : y; }
void swap(int &x,int &y){ int t=x; x=y,y=t; }
void makemin(){
for (int i=n;i;i--){
min[i][]=hi[i];
for (int j=;i+(<<j)<=n;j++)
min[i][j]=minn(min[i][j-],min[i+(<<(j-))][j-]);
}
}
int find(int t){
int l=,r=,mid;
while (l+<r){
mid=(l+r)/;
if ((<<mid)>t) r=mid;
else l=mid;
}
return l;
}
int getlon(int x,int y){
x=rank[x],y=rank[y];
if (x>y) swap(x,y);
int add=find(y-x);
//while ((1<<add)<=y-x) ++add;
//--add;
return minn(min[x+][add],min[y-(<<add)+][add]);
}
bool checkres(int resx,int resy){
if (!ansx) return ;
int l1=resy-resx+,l2=ansy-ansx+,lon=getlon(resx,ansx);
if (lon>=l1 || lon>=l2) return l1<l2;
return rank[resx]<rank[ansx];
}
void makexy(int x,int y,int z){
for (int i=x;i+z-<=y;i++){
int resx=i,resy=i+z-;
if (checkres(resx,resy)) ansx=resx,ansy=resy;
}
}
void makeans(int bo){
for (int i=;i<lon;i++)
for (int j=+i;j<=lon;j+=i)
if (a[j]==a[j-i]){
int resx=j-i-getlon(n-(j-i)+,n-j+)+,resy=j+getlon(j-i,j)-,lon=resy-resx+,res=lon/i;
if (bo){
if (res==ans) makexy(resx,resy,i*res);
}else if (ans<res) ans=res;
}
}
int main(){
freopen("poj3693.in","r",stdin);
freopen("poj3693.out","w",stdout);
for (int t=;scanf("%s",s),s[]!='#';t++){
printf("Case %d: ",t);
lon=strlen(s);
n=;
for (int i=;i<lon;i++) a[++n]=s[i];
a[++n]='~';
for (int i=lon-;i>=;i--) a[++n]=s[i];
a[n+]=;
ans=;
ansx=ansy=;
makesa();
makehi();
makemin();
makeans();
if (ans==) printf("%c\n",s[sa[]-]);
else{
if (t==)
t=;
makeans();
for (int i=ansx;i<=ansy;i++) printf("%c",s[i-]);
puts("");
}
}
fclose(stdin);
fclose(stdout);
}

【po3693】Maximum repetition substring的更多相关文章

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

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

  2. 【poj3693】 Maximum repetition substring

    http://poj.org/problem?id=3693 (题目链接) 题意 给定一个字符串,求重复次数最多的连续重复子串,若存在多组解,输出字典序最小的. Solution 后缀数组论文题,就是 ...

  3. 【POJ3693】Maximum repetition substring (SA)

    这是一道神奇的题目..论文里面说得不清楚,其实是这样...如果一个长度为l的串重复多次,那么至少s[1],s[l+1],s[2*l+1],..之中有相邻2个相等...设这时为j=i*l+1,k=j+l ...

  4. 【Poj-3693】Maximum repetition substring 后缀数组 连续重复子串

    POJ - 3693 题意 SPOJ - REPEATS的进阶版,在这题的基础上输出字典序最小的重复字串. 思路 跟上题一样,先求出最长的重复次数,在求的过程中顺便纪录最多次数可能的长度. 因为sa数 ...

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

    后缀数组的论文里的例题,论文里的题解并没有看懂,,, 求一个重复次数最多的连续重复子串,又因为要找最靠前的,所以扫的时候记录最大的重复次数为$ans$,扫完后再后从头暴力扫到尾找重复次数为$ans$的 ...

  6. 【SPOJ687&POJ3693】Maximum repetition substring(后缀数组)

    题意: n<=1e5 思路: From http://hzwer.com/6152.html 往后匹配多远 r 用ST表求lcp即可...往前 l 就把串反过来再做一下.. 但是有可能求出来的最 ...

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

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

  8. Maximum repetition substring 后缀数组

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

  9. Maximum repetition substring (poj3693 后缀数组求重复次数最多的连续重复子串)

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

随机推荐

  1. django 的mysql数据配置

    原地址:http://blog.csdn.net/gamesofsailing/article/details/21465327 在成功安装python-mysql后,开始配置django的mysql ...

  2. codeforces #305 div1 done

    总算搞定了这一场比赛的题目,感觉收获蛮大 其中A,B,C都能通过自己的思考解决掉 D题思路好神,E题仔细想想也能想出来 以后坚持每两天或者一天做一场CF的div1的全套题目 除非有实在无法做出来的题目 ...

  3. 基于http.sys来开发的,真的是非常稳定

    真正的WEB服务器是不会用Indy写的.因为它是基于每连接每线程的. 其实真正的服务器需要下很多功夫,无法快速开发的.比如说,字符串处理.玩服务器基本上就是玩内存.举个例子: var str:Ansi ...

  4. SQLite数据类型详解

    一.存储种类和数据类型: SQLite将数据值的存储划分为以下几种存储类型: 复制代码代码如下:      NULL: 表示该值为NULL值.      INTEGER: 无符号整型值.      R ...

  5. P107、面试题15:链表中倒数第K个结点

    题目:输入一个链表,输出该链表中倒数第K个结点.为了符合大多数人的习惯,本体从1开始奇数,即链表的尾结点是倒数第1个结点.例如一个链表有6个结点,从头结点开始他们的值一次是1.2.3.4.5.6.这个 ...

  6. NuGet相关的文章

    NuGet学习笔记(1)——初识NuGet及快速安装使用http://www.cnblogs.com/zhwl/p/3377510.html NuGet学习笔记(2) 使用图形化界面打包自己的类库ht ...

  7. PHP的(Thread Safe与Non Thread Safe)

    在安装xdebug到时候你会有有TS和NTS版本的选择,在以前还有VC6和VC9的版本.如果你没有根据你目前的服务器的状况选择对应的版本的话,那么xdebug是安装不成功的. 一.如何选择 php5. ...

  8. C#和.net之间的关系

    What is the difference between C# and .NET? In addition to what Andrew said, it is worth noting that ...

  9. 深入理解Android内存管理原理(六)

    一般来说,程序使用内存的方式遵循先向操作系统申请一块内存,使用内存,使用完毕之后释放内存归还给操作系统.然而在传统的C/C++等要求显式释放内存的编程语言中,记得在合适的时候释放内存是一个很有难度的工 ...

  10. C语言中的malloc和free

    最近在研究php自定义函数的实现,其中php自定义函数在传递参数时,是放到人为的一个栈中,这个跟写C程序时,参数入栈的这个栈还不一样,其中延伸到了 malloc 以及free 有人说在free(p)后 ...