codeforces

链接:https://codeforces.com/contest/427/problem/D
思路:考虑把两个串中间拿个字符隔开,然后后缀数组一波,对于每一个h[i],如果他比相邻两个都要大且两个前缀出现在两个串中,那么我们可以取它相邻两个中的最小值+1更新答案即可(首先如果比相邻两个的某一个小,说明有连续当前这个lcp至少出现3次,肯定不满足题意,当比两边都大时,我们取最小的那一个+1,这样肯定他们只出现两次)

代码

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

using namespace std;
const int maxn = 1e5;
char s[maxn], s1[maxn], s2[maxn];
int sa[maxn],t[maxn],t2[maxn],c[maxn],n,m,k;
int r[maxn],h[maxn];
int ans;



void (int n,int m){//n为原串长度+1,字符值在0-m-1
int i,*x = t,*y = t2;
for(i=0;i<m;i++)c[i] = 0;
for(i=0;i<n;i++)c[x[i]=s[i]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[i]]] = i;
for(int k=1;k<=n;k<<=1){
int p = 0;
for(i=n-k;i<n;i++)y[p++] = i;
for(i=0;i<n;i++)if(sa[i]>=k)y[p++] = sa[i]-k;
for(i=0;i<m;i++)c[i] = 0;
for(i=0;i<n;i++)c[x[y[i]]]++;
for(i=0;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]] = y[i];
swap(x,y);
p = 1;x[sa[0]] = 0;
for(i=1;i<n;i++)
x[sa[i]] = y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n)break;
m = p;
}
}


//最好从0开始,这样sa[n-1] = 0,可以把上一次的数据清空
void getheight(){
int i,j,k = 0;
for(i=0;i<=n;i++)r[sa[i]] = i;
for(i=0;i<n;i++){
if(k)k--;
if(!r[i])continue;
int j = sa[r[i]-1];
while(s[i+k]==s[j+k])k++;
h[r[i]] = k;
}
}

void solve(){
ans = 1e9;
for(int i = 1; i <= n; i++){
if(!h[i])continue;
if((sa[i] > m && sa[i - 1] < m) || (sa[i] < m && sa[i - 1] > m));
else continue;
if(i == 1 && h[i + 1] < h[i])ans = min(ans, h[i + 1] + 1);
else if(i == n && h[i - 1] < h[i]) ans = min(ans, h[i - 1] + 1);
else if(h[i - 1] < h[i] && h[i] > h[i + 1])ans = min(ans, max(h[i - 1], h[i + 1]) + 1);
}
}


int main(){
scanf("%s%s", s1, s2);
n = strlen(s1) + strlen(s2) + 1;
m = strlen(s1);
strcpy(s, s1);
s[m] = '#';
s[m + 1] = '