POJ-3693-Maximum repetition substring(后缀数组-重复次数最多的连续重复子串)
2013-09-06 21:54
615 查看
题意:
给出一个串,求重复次数最多的连续重复子串
分析:
比较容易理解的部分就是枚举长度为L,然后看长度为L的字符串最多连续出现几次。
既然长度为L的串重复出现,那么str[0],str[l],str[2*l]……中肯定有两个连续的出现在字符串中。
那么就枚举连续的两个,然后从这两个字符前后匹配,看最多能匹配多远。
即以str[i*l],str[i*l+l]前后匹配,这里是通过查询suffix(i*l),suffix(i*l+l)的最长公共前缀
通过rank值能找到i*l,与i*l+l的排名,我们要查询的是这段区间的height的最小值,通过RMQ预处理
达到查询为0(1)的复杂度,
设LCP长度为M, 则答案显然为M / L + 1, 但这不一定是最好的, 因为答案的首尾不一定再我们枚举的位置上. 我的解决方法是, 我们考虑M % L的值的意义, 我们可以认为是后面多了M % L个字符, 但是我们更可以想成前面少了(L - M % L)个字符! 所以我们求后缀j * L - (L - M % L)与后缀(j + 1) * L - (L - M % L)的最长公共前缀。
即把之前的区间前缀L-M%L即可。
分析引自/article/2566059.html
给出一个串,求重复次数最多的连续重复子串
分析:
比较容易理解的部分就是枚举长度为L,然后看长度为L的字符串最多连续出现几次。
既然长度为L的串重复出现,那么str[0],str[l],str[2*l]……中肯定有两个连续的出现在字符串中。
那么就枚举连续的两个,然后从这两个字符前后匹配,看最多能匹配多远。
即以str[i*l],str[i*l+l]前后匹配,这里是通过查询suffix(i*l),suffix(i*l+l)的最长公共前缀
通过rank值能找到i*l,与i*l+l的排名,我们要查询的是这段区间的height的最小值,通过RMQ预处理
达到查询为0(1)的复杂度,
设LCP长度为M, 则答案显然为M / L + 1, 但这不一定是最好的, 因为答案的首尾不一定再我们枚举的位置上. 我的解决方法是, 我们考虑M % L的值的意义, 我们可以认为是后面多了M % L个字符, 但是我们更可以想成前面少了(L - M % L)个字符! 所以我们求后缀j * L - (L - M % L)与后缀(j + 1) * L - (L - M % L)的最长公共前缀。
即把之前的区间前缀L-M%L即可。
分析引自/article/2566059.html
// File Name: 3693.cpp // Author: Zlbing // Created Time: 2013年09月06日 星期五 21时05分32秒 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) //rank从0开始 //sa从1开始,因为最后一个字符(最小的)排在第0位 //height从2开始,因为表示的是sa[i-1]和sa[i] const int MAXN=220000; int rank[MAXN],sa[MAXN],X[MAXN],Y[MAXN],height[MAXN]; char s[MAXN]; int buc[MAXN]; void calheight(int n) { int i , j , k = 0; for(i = 1 ; i <= n ; i++) rank[sa[i]] = i; for(i = 0 ; i < n ; height[rank[i++]] = k) for(k?k--:0 , j = sa[rank[i]-1] ; s[i+k] == s[j+k] ; k++); } bool cmp(int *r,int a,int b,int l) { return (r[a] == r[b] && r[a+l] == r[b+l]); } void suffix(int n,int m = 128) { int i , l , p , *x = X , *y = Y; for(i = 0 ; i < m ; i ++) buc[i] = 0; for(i = 0 ; i < n ; i ++) buc[ x[i] = s[i] ] ++; for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1]; for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[i] ]] = i; for(l = 1,p = 1 ; p < n ; m = p , l *= 2) { p = 0; for(i = n-l ; i < n ; i ++) y[p++] = i; for(i = 0 ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l; for(i = 0 ; i < m ; i ++) buc[i] = 0; for(i = 0 ; i < n ; i ++) buc[ x[y[i]] ] ++; for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1]; for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[y[i]] ] ] = y[i]; for(swap(x,y) , x[sa[0]] = 0 , i = 1 , p = 1 ; i < n ; i ++) x[ sa[i] ] = cmp(y,sa[i-1],sa[i],l) ? p-1 : p++; } calheight(n-1);//后缀数组关键是求出height,所以求sa的时候顺便把rank和height求出来 } //当需要反复询问两个后缀的最长公共前缀时用到RMQ int Log[MAXN]; int best[20][MAXN]; void initRMQ(int n) {//初始化RMQ for(int i = 1; i <= n ; i ++) best[0][i] = height[i]; for(int i = 1; i <= Log ; i ++) { int limit = n - (1<<i) + 1; for(int j = 1; j <= limit ; j ++) { best[i][j] = min(best[i-1][j] , best[i-1][j+(1<<i>>1)]); } } } int lcp(int a,int b) {//询问a,b后缀的最长公共前缀 a = rank[a]; b = rank[b]; if(a > b) swap(a,b); a ++; int t = Log[b - a + 1]; return min(best[t][a] , best[t][b - (1<<t) + 1]); } int main() { //预处理每个数字的Log值,常数优化,用于RMQ Log[0] = -1; for(int i = 1; i < MAXN ; i ++) { Log[i] = (i&(i-1)) ? Log[i-1] : Log[i-1] + 1 ; } int cas=0; //******************************************* // n为数组长度,下标0开始 // 将初始数据,保存在s里,并且保证每个数字都比0大 // m = max{ s[i] } + 1 // 一般情况下大多是字符操作,所以128足够了 //******************************************* while(~scanf("%s",s)) { if(s[0]=='#')break; int n=strlen(s); s =0; suffix(n+1); initRMQ(n); int maxx=0; int len=0; int pos=0; for(int i=1;i<=n/2;i++) { for(int j=0;j+i<n;j+=i) { if(s[j]!=s[j+i])continue; int k=lcp(j,j+i); int tot=k/i+1; int t=i-(k%i); int p=j; int cnt=0; if(t&&t<i) { for(int m=j-1;m>j-i&&s[m]==s[m+i]&&m>=0;m--) { cnt++; if(cnt==t) { tot++; p=m; } else if(rank[p]>rank[m]) { p=m; } } } if(tot>maxx) { maxx=tot; pos=p; len=maxx*i; } else if(tot==maxx) { if(rank[p]<rank[pos]) { pos=p; len=maxx*i; } } } } printf("Case %d: ",++cas); if(maxx<2) { char ch='z'; for(int i=0;i<n;i++) if(s[i]<ch) ch=s[i]; printf("%c\n",ch); continue; } for(int i=pos;i<pos+len;i++) printf("%c",s[i]); printf("\n"); } return 0; }
相关文章推荐
- POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)
- POJ 3693 Maximum repetition substring(后缀数组[重复次数最多的连续重复子串])
- POJ 3693 Maximum repetition substring 后缀数组求重复次数最多子串
- Poj 3693 & Hdu 2459 Maximum repetition substring (08合肥Online 后缀数组+RMQ 重复次数最多的连续重复子串)
- 【POJ 3693】Maximum repetition substring 重复次数最多的连续重复子串
- POJ 3693 Maximum repetition substring (寻找重复次数最多的连续子串)
- POJ 3693 Maximum repetition substring(重复次数最多的连续子串 字典序最小)
- poj 3693 后缀数组 重复次数最多的连续重复子串
- poj 3693 Maximum repetition substring 重复次数最多的子串(若有多个 输出字典序最小的子串) 后缀数组 (DC3) (SA)
- POJ 3693 Maximum repetition substring (后缀数组+RMQ 求重复最多的连续子串)
- poj 3693 后缀数组求重复次数最多的连续重复子串
- 【后缀数组求重复次数最多的连续重复子串】SPOJ687 POJ3693
- poj 3693 后缀数组 重复次数最多的连续重复子串
- POJ 3693 Maximum repetition substring(后缀数组求最长重复子串)
- POJ 3693 Maximum repetition substring (后缀数组+RMQ 求重复最多的连续子串)
- 【POJ】3693 Maximum repetition substring 【后缀数组——求最长连续重复字串】
- POJ 3693 重复次数最多的连续重复子串 后缀数组
- POJ 题目 3693 Maximum repetition substring(后缀数组+RMQ+枚举求最小字典序的重复次数最多的子串)
- POJ 3693 Maximum repetition substring (后缀数组+RMQ 求重复最多的连续子串)
- poj 3693 后缀数组 重复次数最多的连续重复子串