POJ 3693 (后缀数组) Maximum repetition substring

找重复次数最多的字串,如果有多解,要求字典序最小。

我也是跟着罗穗骞菊苣的论文才刷这道题的。

首先还是枚举一个循环节的长度L,如果它出现两次的话,一定会包含s[0], s[L], s[2L]这些相邻两个之间。

然后枚举相邻的两个,尽可能的向前和向后延伸,假设延伸长度为k,则重复次数为k / L + 1

向后延伸很自然的就是求一次LCP,这个用RMQ预处理一下就可以O(1)查询。

向前延伸就是考虑到,我们枚举的s[i*L]和s[(i+1)*L]并不一定是字串的开头,所以向前移动i - (k % i)个位置。

为什么向前移动这么多,就是因为这样的话,LCP的长度就正好是i的整数倍了。

所以向前移动以后,再求一次LCP,看看能否够i - (k % i)这么多,够的话这个串的重复次数再加1.

至于要字典序最小,就得用height数组天生自带字典序。把所有重复次数最多的长度记录下来,然后按字典序枚举,只要找到一组就输出。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 using namespace std;
  5
  6 const int maxn = 100000 + 10;
  7 char s[maxn];
  8 int n;
  9 int sa[maxn], rank[maxn], height[maxn];
 10 int t[maxn], t2[maxn], c[256];
 11
 12 void build_sa(int n, int m)
 13 {
 14     int i, *x = t, *y = t2;
 15     for(i = 0; i < m; i++) c[i] = 0;
 16     for(i = 0; i < n; i++) c[x[i] = s[i]]++;
 17     for(i = 1; i < m; i++) c[i] += c[i - 1];
 18     for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
 19     for(int k = 1; k <= n; k <<= 1)
 20     {
 21         int p = 0;
 22         for(i = n - k; i < n; i++) y[p++] = i;
 23         for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
 24         for(i = 0; i < m; i++) c[i] = 0;
 25         for(i = 0; i < n; i++) c[x[y[i]]]++;
 26         for(i = 1; i < m; i++) c[i] += c[i - 1];
 27         for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
 28         swap(x, y);
 29         p = 1; x[sa[0]] = 0;
 30         for(i = 1; i < n; i++)
 31             x[sa[i]] = y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? p - 1 : p++;
 32         if(p >= n) break;
 33         m = p;
 34     }
 35 }
 36
 37 void build_height()
 38 {
 39     int k = 0;
 40     for(int i = 1; i <= n; i++) rank[sa[i]] = i;
 41     for(int i = 0; i < n; i++)
 42     {
 43         if(k) k--;
 44         int j = sa[rank[i] - 1];
 45         while(s[i + k] == s[j + k]) k++;
 46         height[rank[i]] = k;
 47     }
 48 }
 49
 50 int d[maxn][20];
 51
 52 void init_RMQ()
 53 {
 54     for(int i = 0; i < n; i++) d[i][0] = height[i + 1];
 55     for(int j = 1; (1 << j) <= n; j++)
 56         for(int i = 0; i + (1 << j) - 1 < n; i++)
 57             d[i][j] = min(d[i][j-1], d[i + (1<<(j-1))][j-1]);
 58 }
 59
 60 int RMQ(int L, int R)
 61 {
 62     int k = 0;
 63     while( (1 << (k+1)) <= (R - L + 1) ) k++;
 64     return min(d[L][k], d[R-(1<<k)+1][k]);
 65 }
 66
 67 int LCP(int i, int j)
 68 {
 69     i = rank[i] - 1; j = rank[j] - 1;
 70     if(i > j) swap(i, j);
 71     return RMQ(i + 1, j);
 72 }
 73
 74 int a[maxn], cnt, maxl;
 75
 76 int main()
 77 {
 78     //freopen("in.txt", "r", stdin);
 79
 80     int kase = 0;
 81     while(scanf("%s", s) == 1 && s[0] != ‘#‘)
 82     {
 83         n = strlen(s);
 84         build_sa(n + 1, 256);
 85         build_height();
 86         init_RMQ();
 87
 88         cnt = maxl = 0;
 89         for(int i = 1; i < n; i++)
 90         {
 91             for(int j = 0; j + i < n; j += i)
 92             {
 93                 int k = LCP(j, j + i);
 94                 int t = k / i + 1;
 95                 int left = i - (k % i);
 96                 int head = j - left;
 97                 if(head >= 0 && LCP(head, head + i) >= left) t++;
 98                 if(t > maxl)
 99                 {
100                     cnt = 0;
101                     a[cnt++] = i;
102                     maxl = t;
103                 }
104                 if(t == maxl) a[cnt++] = i;
105             }
106         }
107
108         int len = -1, st;
109         for(int i = 1; i <= n && len == -1; i++)
110         {
111             for(int j = 0; j < cnt; j++)
112             {
113                 int l = a[j];
114                 if(LCP(sa[i], sa[i] + l) >= (maxl - 1) * l)
115                 {
116                     len = l;
117                     st = sa[i];
118                     break;
119                 }
120             }
121         }
122
123         printf("Case %d: ", ++kase);
124         for(int i = 0; i < len * maxl; i++) printf("%c", s[st + i]);
125         puts("");
126     }
127
128     return 0;
129 }

代码君

时间: 2024-08-08 04:35:47

POJ 3693 (后缀数组) Maximum repetition substring的相关文章

POJ - 2406 ~SPOJ - REPEATS~POJ - 3693 后缀数组求解重复字串问题

POJ - 2406 题意: 给出一个字符串,要把它写成(x)n的形式,问n的最大值. 这题是求整个串的重复次数,不是重复最多次数的字串 这题很容易想到用KMP求最小循环节就没了,但是后缀数组也能写 后缀数组写法放在后面那一题,SPOJ - REPEATS是求子串类型,KMP就不好处理了 这里放下处理KMP的AC代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <c

POJ 3693 后缀数组+RMQ

点击打开链接 题意:问连续重复部分最多的串是什么,不能重叠,且我们要字典序最小的串如xbcabcab,有bcabca重复次数为2,cabcab重复次数也为2,那么要前边那个 思路:以前写过一个类似的,SPOJ 687,这个只是求连续重复部分最多的串的次数,并不需要将按字典序最小串输出,那么我们可以用到SPOJ687的代码,用它我们可以求出那个重复的次数和满足这个次数的串的长度,那么就只差找到字典序最小的那个串了,而我们知道后缀数组的sa数组就是按字典序来的嘛,从字典序最小开始找,找到就跳出,输出

poj 3693 后缀数组求重复次数最多的连续重复子串

#include<iostream> #include<cstring> #include<set> #include<map> #include<cmath> #include<stack> #include<queue> #include<deque> #include<list> #include<algorithm> #include<stdio.h> #includ

poj 3693 Maximum repetition substring(后缀数组)

题目链接:poj 3693 Maximum repetition substring 题目大意:求一个字符串中循环子串次数最多的子串. 解题思路:对字符串构建后缀数组,然后枚举循环长度,分区间确定.对于一个长度l,每次求出i和i+l的LCP,那么以i为起点,循环子串长度为l的子串的循环次数为LCP/l+1,然后再考虑一下从i-l+1~i之间有没有存在增长的可能性. #include <cstdio> #include <cstring> #include <vector>

POJ 3693 Maximum repetition substring (后缀数组)

题目大意: 求出字典序最小,重复次数最多,的子串. 思路分析: RMQ + height 数组可以求出任意两个后缀的lcp 我们枚举答案字符串的重复的长度. 如果这个字符串的长度为 l ,而且这个字符串出现过两次或两次以上 那么你会发现在原串中  str[0] str[l] str[2*l] ....肯定有相邻的两个被包含在重复的串中. 我们求出这两个相邻的后缀的lcp 我们上面仅仅说的是被包含在重复的串中,但并不一定就是以 str[0], str[l],str[2*l]....为起点的. 那我

POJ 3693 Maximum repetition substring(后缀数组神题)

POJ 3693 Maximum repetition substring 题目链接 题意:给定一个字符串,求出其子串中,重复次数最多的串,如果有相同的,输出字典序最小的 思路:枚举长度l,把字符串按l分段,这样对于长度为l的字符串,肯定会包含一个分段位置,这样一来就可以在每个分段位置,往后做一次lcp,求出最大匹配长度,然后如果匹配长度有剩余,看剩余多少,就往前多少位置再做一次lcp,如果匹配出来长度更长,匹配次数就加1,这样就可以枚举过程中保存下答案了 这样问题还有字典序的问题,这个完全可以

POJ 3693 Maximum repetition substring(后缀数组+RMQ)

Maximum repetition substring 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&quo

poj 3693 Maximum repetition substring(有点麻烦的后缀数组)

Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6638   Accepted: 2007 Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same conse

POJ 题目 3693 Maximum repetition substring(后缀数组+RMQ+枚举求最小字典序的重复次数最多的子串)

Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8067   Accepted: 2463 Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same conse