1. 程式人生 > >Maximum repetition substring POJ

Maximum repetition substring POJ

又是一道字尾陣列的題目,和上一道題目是類似的,不過要輸字串本身,在同等重複次數下輸出,字典序最小的。
我們只需要記錄下所有達到最大重複次數的,重複段的長度就可以了,然後按照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; }