0%

 HDU - 1403-最长公共子串

思路讲解

假设已经知道height数组以及后缀数组,这样子求出来的就是最长公共子串

1
2
3
4
5
6
7
8
9
10
S=s1+'$'+s2;
for(int i=1;i<N;++i){
ll l=sa[i-1],r=sa[i];
if(l>r)
swap(l, r);
if(l<n1 && r>n1){
ans=max(ans,height[i]);
}
}
cout<<ans<<'\n';

AC代码

AC 倍增法还是快

https://vjudge.net/solution/57548921

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <deque>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cmath>
#include <bitset>
#include <iterator>
#include <random>
#include <iomanip>
#include <cctype>
#include <array>

using namespace std;

typedef long long ll;
typedef pair<ll,ll> pll;
typedef array<ll,3> arr;
const ll MAXN=static_cast<ll>(2e5)+10;
const ll base=131;

ll N,tmp[MAXN],sa[MAXN],height[MAXN],rk[MAXN],K;
string S;

bool comp_sa(ll a,ll b){
if(rk[a]!=rk[b]){
return rk[a]<rk[b];
}else{
int ra= a+K<=N ? rk[a+K]:-1;
int rb= b+K<=N ? rk[b+K]:-1;
return ra<rb;
}
}

inline void cal_sa(){ // 计算后缀数组
// tmp要访问到第N个数
for(int i=0;i<=N;++i){
rk[i]=i<N ? S[i]:-1;
sa[i]=i; // 还没有排序的后缀数组
}
for(K=1;K<=N;K=K*2){
sort(sa, sa+N, comp_sa);
// 排在sa最前面的rk肯定也是最前面的
tmp[sa[0]]=0;
for(int i=0;i<N;++i){
// tmp[sa[0]]排第一个,tmp[sa[0]]为第
// 如果确实小,rk+1(因为这个rk要排logn次,不是一次排出来的)
tmp[sa[i+1]]=tmp[sa[i]]+(comp_sa(sa[i], sa[i+1]) ? 1:0);
}
for(int i=0;i<N;++i){
rk[i]=tmp[i];
}
}
}

inline void getHeight(){
for(int i=0;i<N;++i){
rk[sa[i]]=i;
}
for(int i=0,k=0;i<N;++i){
if(rk[i]==0) continue;
if(k) k--;
int j=sa[rk[i]-1]; // 前面一个序列的起始位置
while (i+k<N && j+k<N && S[i+k]==S[j+k]) k++;
height[rk[i]]=k;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
string s1,s2;
while(cin>>s1>>s2){
S=s1+'$'+s2;
N=S.size();
cal_sa();
getHeight();
// < n1 是前面的串 >n1 是后面的串
ll n1=s1.size();
ll ans=0;
for(int i=1;i<N;++i){
ll l=sa[i-1],r=sa[i];
if(l>r)
swap(l, r);
if(l<n1 && r>n1){
ans=max(ans,height[i]);
}
}
cout<<ans<<'\n';
}
return 0;
}
/*
AC https://vjudge.net/solution/57548921
banana
cianaic
abbacc
abbaccc

EOF

*/

心路历程(WA,TLE,MLE……)

https://vjudge.net/solution/57547694

TLE,我用快读试试能不能搞定用哈希二分过