POJ 3693 Maximum repetition substring (后缀数组)
来源:互联网 发布:淘宝执行运营工资高吗 编辑:程序博客网 时间:2024/04/18 05:40
题目大意:
求出字典序最小,重复次数最多,的子串。
思路分析:
RMQ + height 数组可以求出任意两个后缀的lcp
我们枚举答案字符串的重复的长度。
如果这个字符串的长度为 l ,而且这个字符串出现过两次或两次以上
那么你会发现在原串中 str[0] str[l] str[2*l] ....肯定有相邻的两个被包含在重复的串中。
我们求出这两个相邻的后缀的lcp
我们上面仅仅说的是被包含在重复的串中,但并不一定就是以 str[0], str[l],str[2*l]....为起点的。
那我们就要往前去寻找这个起点。
也不是往前枚举,可以发现只要往前移动 l-lcp%l 个位置。
比如。
xbcabcab
当 l = 3 的时候
你找到了
ab
abcab
发现 lcp = 2,然后往前减去一个 l-lcp%l ,结果cab和cabcab的lcp 变成了3
也就是说往前寻找可以再补齐一个周期。
再讨论字典序最小的问题。
在sa中找到的第一个,满足最长的重复次数和长度的也就是字典序最小的了。
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#define maxn 100005using namespace std;char str[maxn];int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;void suffix(int m){ int *x=t1,*y=t2; for(int i=0; i<m; i++)c[i]=0; for(int i=0; i<n; i++)c[x[i]=str[i]]++; for(int i=1; i<m; i++)c[i]+=c[i-1]; for(int i=n-1; i>=0; i--)sa[--c[x[i]]]=i; for(int k=1; k<=n; k<<=1) { int p=0; for(int i=n-k; i<n; i++)y[p++]=i; for(int i=0; i<n; i++)if(sa[i]>=k)y[p++]=sa[i]-k; for(int i=0; i<m; i++)c[i]=0; for(int i=0; i<n; i++)c[x[y[i]]]++; for(int i=0; i<m; i++)c[i]+=c[i-1]; for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for(int i=1; i<n; i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n)break; m=p; }}int rank[maxn],height[maxn];void getheight(){ int k=0; for(int i=0; i<n; i++)rank[sa[i]]=i; for(int i=0; i<n; i++) { if(k)k--; if(!rank[i])continue; int j=sa[rank[i]-1]; while(str[i+k]==str[j+k])k++; height[rank[i]]=k; }}int f[maxn][30];void RMQINIT(){ for(int i=0;i<n;i++) f[i][0]=height[i]; for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)-1<n;i++) f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);}int RMQ(int l,int r){ if(l>r)swap(l,r); l++; int k=floor(log(r-l+1.0)/log(2.0)); return min(f[l][k],f[r+1-(1<<k)][k]);}int ans[maxn];int main(){ int cas=1; while(scanf("%s",str)!=EOF && str[0]!='#') { n=strlen(str); str[n]=0; n++; suffix(128); getheight(); RMQINIT(); int Max=0; int top=0; for(int l=1;l<n;l++) { for(int i=l;i<n;i+=l) { int lcp=RMQ(rank[i-l],rank[i]); int repeat = lcp/l+1; int st = i-(l-lcp%l); if(st>=l && lcp%l) { if(RMQ(rank[st-l],rank[st])>=lcp) repeat++; } if(repeat>Max) { Max=repeat; top=0; ans[top++]=l; } else if(repeat==Max)ans[top++]=l; } } int len=-1,st; for(int i=1;i<n && len==-1;i++) for(int j=0;j<top;j++) { if(RMQ(rank[sa[i]],rank[sa[i]+ans[j]])>=(Max-1)*ans[j]) { len=ans[j]; st=sa[i]; break; } } printf("Case %d: ",cas++); for(int i=st;i<st+len*Max;i++) printf("%c",str[i]); puts(""); } return 0;}
0 0
- poj 3693 Maximum repetition substring //后缀数组
- poj 3693 Maximum repetition substring (后缀数组)
- poj 3693 Maximum repetition substring(后缀数组)
- poj 3693 Maximum repetition substring(后缀数组)
- 【后缀数组】【poj 3693】Maximum repetition substring
- POJ 3693 Maximum Repetition Substring 后缀数组
- poj 3693 Maximum repetition substring(后缀数组好题)
- POJ 3693 Maximum repetition substring(RMQ+后缀数组)
- POJ 3693 Maximum repetition substring (后缀数组)
- POJ 3693 - Maximum repetition substring (后缀数组)
- POJ 3693 Maximum repetition substring(后缀数组)
- POJ 3693 Maximum repetition substring(后缀数组+ST)
- poj 3693 Maximum repetition substring (后缀数组+RMQ)
- 【后缀数组】 HDOJ 2459 && POJ 3693 Maximum repetition substring
- poj 3693 Maximum repetition substring(有点麻烦的后缀数组)
- POJ 3693 Maximum repetition substring(后缀数组神题)
- [后缀数组+枚举] hdu 2459 && poj 3693 Maximum repetition substring
- poj 3693 Maximum repetition substring 后缀数组+RMQ
- libGDX视频教程(一) -- 初识libGDX
- iOS设计模式之四:备忘录模式和命令模式
- 推荐一款好用的jquery弹出层插件——wbox
- SVN权限配置
- 总有一些缘,自认为刻骨铭心,而美丽难以触及
- POJ 3693 Maximum repetition substring (后缀数组)
- HuaweiOJ-扑克牌大小
- yii2中集成使用kindeditor富文本编辑器
- AnimatePacker3.0接口封装
- Swift中文教程(七) 闭包
- 分布式缓存中三种负载均衡的方法
- GPG key retrieval failed: [Errno 14] Could not open/read file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-
- nginx rewrite 指令last break区别
- c++ 开源日志库选择