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 }
代码君

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。