1. 题目描述
给定一个长为$n in [1, 4000]$的字符串,求其中长度最长的子串,并且该子串在原串中出现至少$m$次,并求最右起始位置。
2. 基本思路
两种方法:二分+后缀数组,或者二分+哈希。
(1) 二分+后缀数组
对子串长度进行二分,若不同后缀的公共前缀超过这个值,则对计数值累加。若计数值超过m,则证明这个公共前缀是有效的,计数过程中同时维护pos(最右边界),从而更新rpos。
(2)二分+哈希
仍然是对长度进行二分,然后枚举其实位置计算该长度的子串的哈希值,排序后,计算,超过m表示是有效的子串,从而更新最右位置。哈希采用LCP哈希。
3. 代码
(1)后缀数组
1 /* 4080 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <algorithm> 12 #include <cstdio> 13 #include <cmath> 14 #include <ctime> 15 #include <cstring> 16 #include <climits> 17 #include <cctype> 18 #include <cassert> 19 #include <functional> 20 #include <iterator> 21 #include <iomanip> 22 using namespace std; 23 //#pragma comment(linker,"/STACK:102400000,1024000") 24 25 #define sti set<int> 26 #define stpii set<pair<int, int> > 27 #define mpii map<int,int> 28 #define vi vector<int> 29 #define pii pair<int,int> 30 #define vpii vector<pair<int,int> > 31 #define rep(i, a, n) for (int i=a;i<n;++i) 32 #define per(i, a, n) for (int i=n-1;i>=a;--i) 33 #define clr clear 34 #define pb push_back 35 #define mp make_pair 36 #define fir first 37 #define sec second 38 #define all(x) (x).begin(),(x).end() 39 #define SZ(x) ((int)(x).size()) 40 #define lson l, mid, rt<<1 41 #define rson mid+1, r, rt<<1|1 42 43 const int maxn = 40005; 44 char s[maxn]; 45 int a[maxn]; 46 int height[maxn], sa[maxn], rrank[maxn]; 47 int wa[maxn], wb[maxn], wc[maxn], wv[maxn]; 48 int rpos, m; 49 50 bool cmp(int *r, int a, int b, int l) { 51 return r[a]==r[b] && r[a+l]==r[b+l]; 52 } 53 54 void da(int *r, int *sa, int n, int m) { 55 int i, j, *x=wa, *y=wb, *t, p; 56 57 for (i=0; i<m; ++i) wc[i] = 0; 58 for (i=0; i<n; ++i) wc[x[i]=r[i]]++; 59 for (i=1; i<m; ++i) wc[i] += wc[i-1]; 60 for (i=n-1; i>=0; --i) sa[--wc[x[i]]] = i; 61 for (j=1,p=1; p<n; j*=2, m=p) { 62 for (p=0, i=n-j; i<n; ++i) y[p++] = i; 63 for (i=0; i<n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j; 64 for (i=0; i<n; ++i) wv[i] = x[y[i]]; 65 for (i=0; i<m; ++i) wc[i] = 0; 66 for (i=0; i<n; ++i) wc[wv[i]]++; 67 for (i=1; i<m; ++i) wc[i] += wc[i-1]; 68 for (i=n-1; i>=0; --i) sa[--wc[wv[i]]] = y[i]; 69 for (t=x,x=y,y=t,x[sa[0]]=0,p=1,i=1; i<n; ++i) 70 x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++; 71 } 72 } 73 74 void calheight(int *r, int *sa, int n) { 75 int i, j, k = 0; 76 77 for (i=1; i<=n; ++i) rrank[sa[i]] = i; 78 for (i=0; i<n; height[rrank[i++]]=k) 79 for (k?k--:0, j=sa[rrank[i]-1]; r[j+k]==r[i+k]; ++k) ; 80 } 81 82 void printSa(int n) { 83 for (int i=1; i<=n; ++i) 84 printf("%d ", sa[i]); 85 putchar(' '); 86 } 87 88 void printHeight(int n) { 89 for (int i=1; i<=n; ++i) 90 printf("%d ", height[i]); 91 putchar(' '); 92 } 93 94 bool judge(int bound, int n) { 95 int cnt = 1, pos = -1; 96 97 rpos = -1; 98 rep(i, 1, n+1) { 99 if (height[i] >= bound) { 100 pos = max(pos, sa[i]); 101 ++cnt; 102 } else { 103 if (cnt >= m) 104 rpos = max(pos, rpos); 105 pos = sa[i]; 106 cnt = 1; 107 } 108 } 109 if (cnt >= m) 110 rpos = max(pos, rpos); 111 112 return rpos!=-1; 113 } 114 115 void solve() { 116 int n; 117 118 for (int i=0; ; ++i) { 119 if (s[i] == '