Maximum repetition substring POJ
阿新 • • 發佈:2018-12-29
又是一道字尾陣列的題目,和上一道題目是類似的,不過要輸字串本身,在同等重複次數下輸出,字典序最小的。
我們只需要記錄下所有達到最大重複次數的,重複段的長度就可以了,然後按照sa陣列排序好的字典序,對每一個sa[i],去列舉記錄下來的重複長度,如果剛好達到要求直接輸出就行了。
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define Max_N (2*50000 + 100)
int n;
int k;
int a[Max_N];
int rank1[Max_N];
int tmp[Max_N];
bool compare_sa(int i, int j)
{
if(rank1[i] != rank1[j]) return rank1[i] < rank1[j];
else {
int ri = i + k <= n ? rank1[i + k] : -1;
int rj = j + k <= n ? rank1[j + k] : -1;
return ri < rj;
}
}
void construct_sa(int buf[], int s, int sa[])
{
int len = s;
for (int i = 0; i <= len; i++) {
sa[i] = i;
rank1[i] = i < len ? buf[i] : -1;
}
for ( k = 1; k <= len; k *= 2) {
sort(sa, sa + len +1, compare_sa);
tmp[sa[0]] = 0;
for (int i = 1; i <= len; i++) {
tmp[sa[i]] = tmp[sa[i-1 ]] + (compare_sa(sa[i-1], sa[i]) ? 1 : 0);
}
for (int i = 0; i <= len; i++) {
rank1[i] = tmp[i];
}
}
}
void construct_lcp(int buf[], int len, int *sa, int *lcp)
{
int h = 0;
lcp[0] = 0;
for (int i = 0; i < len; i++) {
int j = sa[rank1[i] - 1];
if (h > 0) h--;
for (; j + h < len && i + h < len; h++) {
if (buf[j+h] != buf[i+h]) break;
}
lcp[rank1[i] - 1] = h;
}
}
int sa[Max_N];
int rev[Max_N];
int lcp[Max_N];
char buf[Max_N];
int f[Max_N][30];
void rmq()
{
for (int i = 1; i <= n; i++)
f[i][0] = lcp[i];
f[n][0] = 1000000;
for (int j=1; (1<<j) <= n ; j++)
for (int i=1; i+(1<<j)-1<=n; i++)
f[i][j]= min(f[i][j-1],f[i+(1<<j-1)][j-1]);
return;
}
int lcp1(int L, int R)
{
if (L> R) {
int ss = R;
R = L;
L = ss;
}
R--;
int k1 = 0;
while((1<<(k1+1)) <= R-L+1) k1++;
return min(f[L][k1], f[R-(1<<k1)+1][k1]);
}
vector<int> v;
int main()
{
int T;
T = 0;
while (true) {
scanf("%s", buf);
if (buf[0] == '#') return 0;
n = strlen(buf);
for (int i = 0; i < n; i++)
a[i] = int(buf[i]);
a[n] = 0;
construct_sa(a, n, sa);
construct_lcp(a, n, sa, lcp);
rmq();
/*int l,r;
cin >> l >> r;
cout << lcp1(l, r) << endl;*/
int max = 0;
v.clear();
for (int i = 1; i <= n; i++) {
for (int j = 0; j + i < n; j += i) {
int k1 = lcp1(rank1[j], rank1[j+i]);
int r = k1 / i + 1;
int t = j - (i - k1%i);
if (t >= 0)
if (lcp1(rank1[t], rank1[t+i]) >= i) {
r++;
}
if (r > max) {
max = r;
v.clear();
v.push_back(i);
}
if (r == max) {
v.push_back(i);
}
}
}
int beg = 0;
int len = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < v.size(); j++) {
if (sa[i] + v[j] <= n) {
if (lcp1(i, rank1[sa[i]+v[j]]) >= (max-1) * v[j]) {
beg = sa[i];
len = v[j] * max;
i = n+1;
j = v.size() + 1;
}
}
}
}
printf("Case %d: ", ++T);
for (int i = beg; i < beg + len; i++)
printf("%c", buf[i]);
cout << endl;
}
return 0;
}