P5546 [POI2000]公共串
所有串合在一起,每两个串放不同的字符,求一遍后缀数组,然后利用height数组求LCS即可。
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
//sa是排名i的编号,rk是i排名几
int sa[N],rk[N],height[N],cnt[N],oldrk[N],id[N];
string s = "1",b;
int n;
int st[N][20];
void build_sa(){
n = s.length();
--n;
for(int i = 1; i <= n; i++){
rk[i] = s[i];
++cnt[rk[i]];
}
int m = 127,p;
for(int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for(int i = n; i >= 1; i--) sa[cnt[rk[i]]--] = i;
memcpy(oldrk,rk,sizeof rk);
int i;
for(p = 0,i = 1; i <= n; i++){
if(oldrk[sa[i]] == oldrk[sa[i - 1]]){
rk[sa[i]] = p;
}else{
rk[sa[i]] = ++p;
}
}
int w;
for(w = 1; w < n; w <<= 1,m = n){
for(int j = 0; j <= n; j++) cnt[j] = 0;
memcpy(id,sa,sizeof sa);
for(int i = 1; i <= n; i++) ++cnt[rk[id[i] + w]];
for(int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for(int i = n; i >= 1; i--) sa[cnt[rk[id[i] + w]]--] = id[i];
for(int j = 0; j <= n; j++) cnt[j] = 0;
memcpy(id,sa,sizeof sa);
for(int i = 1; i <= n; i++) ++cnt[rk[id[i]]];
for(int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for(int i = n; i >= 1; i--) sa[cnt[rk[id[i]]]--] = id[i];
memcpy(oldrk,rk,sizeof rk);
for(int p = 0,i = 1; i <= n; i++){
if(oldrk[sa[i]] == oldrk[sa[i - 1]]
&& oldrk[sa[i] + w] == oldrk[sa[i - 1] + w]
){
rk[sa[i]] = p;
}else{
rk[sa[i]] = ++p;
}
}
}
for(int i = 1,k = 0; i <= n; i++){
if(rk[i] == 0) continue;
if(k) --k;
while(s[i + k] == s[sa[rk[i] - 1] + k]) ++k;
height[rk[i]] = k;
}
}
void build_st(){
for(int i = 1; i <= n; i++) st[i][0] = height[i];
for(int j = 1; j <= 19; j++)
for(int i = 1; i <= n && i + (1 << j - 1) <= n; i++){
st[i][j] = min(st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
}
}
int query2(int l,int r){
int d = log2(r - l + 1);
return min(st[l][d],st[r - (1 << d) + 1][d]);
}
int max(int x,int y){
if(x > y) return x;
return y;
}
int C[10];
int main(){
int m;
cin >> m;
for(int i = 1; i <= m; i++){
cin >> b;
s += b;
s += char('A' + i - 1);
C[i] = C[i - 1] + b.length() + 1;
}
if(m == 1){
cout << s.length() - 1 << endl;
return 0;
}
build_sa();
build_st();
memset(id,0,sizeof id);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(sa[i] < C[j]){
id[i] = j;
break;
}
}
}
//for(int i = 1; i <= n; i++) cout << height[i] << endl;
int maxn2 = 0;
int flag[10];
for(int i = 1; i <= n; i++){
int cnt = 0;
memset(flag,0,sizeof flag);
for(int j = i; j <= n; j++){
flag[id[j]]++;
if(id[j] != 0 && flag[id[j]] == 1) cnt++;
if(cnt == m){
maxn2 = max(maxn2,query2(i + 1,j));
//cout << i << " " << j << " " << maxn2 << endl;
break;
}
}
}
cout << maxn2 << endl;
return 0;
}
SP1811 LCS - Longest Common Substring
如上做法
LCS2 - Longest Common Substring II
放弃st表,使用单调队列优化即可。
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 2e6 + 10;
//sa是排名i的编号,rk是i排名几
int sa[N],rk[N],height[N],cnt[N],oldrk[N],id[N],key1[N];
string s = "1",b;
int n;
int st[N][22];
void build_sa(){
n = s.length();
--n;
memset(rk,0,sizeof rk);
memset(cnt,0,sizeof cnt);
memset(sa,0,sizeof sa);
for(int i = 1; i <= n; i++){
rk[i] = s[i];
++cnt[rk[i]];
}
int m = 127,p,i;
for(int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for(int i = n; i >= 1; i--) sa[cnt[rk[i]]--] = i;
int w;
for(w = 1;; w <<= 1,m = p){
for(p = 0,i = n; i > n - w; --i) id[++p] = i;
for(int i = 1; i <= n; i++) if(sa[i] > w) id[++p] = sa[i] - w;
memset(cnt,0,sizeof cnt);
for(int i = 1; i <= n; i++) ++cnt[key1[i] = rk[id[i]]];
for(int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for(int i = n; i >= 1; i--) sa[cnt[key1[i]]--] = id[i];
memcpy(oldrk,rk,sizeof rk);
for(p = 0,i = 1; i <= n; i++){
if(oldrk[sa[i]] == oldrk[sa[i - 1]]
&& oldrk[sa[i] + w] == oldrk[sa[i - 1] + w]
){
rk[sa[i]] = p;
}else{
rk[sa[i]] = ++p;
}
}
if(p == n){
for(int i = 1; i <= n; i++) sa[rk[i]] = i;
break;
}
}
for(int i = 1,k = 0; i <= n; i++){
if(rk[i] == 0) continue;
if(k) --k;
while(s[i + k] == s[sa[rk[i] - 1] + k]) ++k;
height[rk[i]] = k;
}
}
int max(int x,int y){
if(x > y) return x;
return y;
}
int C[12];
int main(){
ios::sync_with_stdio(false);
int m = 0;
s = "1";
while(cin >> b){
++m;
s += b;
s += char('A' + m - 1);
C[m] = C[m - 1] + b.length() + 1;
}
if(m == 1){
cout << s.length() - 2 << endl;
return 0;
}
build_sa();
memset(id,0,sizeof id);
for(int i = m + 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(sa[i] < C[j]){
id[i] = j;
break;
}
}
}
//for(int i = 1; i <= n; i++) cout << height[i] << endl;
int maxn2 = 0;
int flag[20] = {};
int k = m + 1;
int cnt = 0;
static int q[N];
int st = 1,ed = 0;
for(int i = m + 1; i <= n; i++){
while(q[st] <= i && st <= ed) st++;
if(cnt == m){
maxn2 = max(maxn2,height[q[st]]);
flag[id[i]]--;
if(id[i] != 0 && flag[id[i]] == 0) cnt--;
continue;
}
for(int j = k; j <= n; j++){
flag[id[j]]++;
while(height[j] <= height[q[ed]] && ed >= st) ed--;
q[++ed] = j;
if(id[j] != 0 && flag[id[j]] == 1) cnt++;
if(cnt == m){
maxn2 = max(maxn2,height[q[st]]);
k = j + 1;
break;
}
k = j + 1;
}
flag[id[i]]--;
if(id[i] != 0 && flag[id[i]] == 0) cnt--;
}
cout << maxn2 << endl;
return 0;
}