codeforces 427D. Match & Catch 後綴數組

題意:

求a b兩個串的最短公共子串長度,且這個子串在a串只出現過一次,在b串也只出現過一次

題解:

先把ab兩個串連在一起形成一個新的串,中間用‘ ’空格符號隔開,用來區分兩個串。

先跑一下後綴數組,利用height數組來求解。在i,向左找到第一個j1使,height[j1]<height[i],向右找到第一個j2,

使height[j2]<height[i]。j2-j1-1的值等於長度爲height[i]的串出現了多少次。題目要求在各串只出現了一次的公共子串,這兩個字串在sa數組裏一定是相鄰的,即sa[i],sa[i-1],且滿足

1,sa[i]和sa[i-1]屬於原先不同的串

2.串sa[i-2]和串sa[i-1]的公共子串長度和串sa[i]和串sa[i+1]的公共子串長度小於串sa[i-1]和串sa[i]的公共子串長度,即

height[i-1]<height[i]&&height[i]>height[i+1]

此時,max(height[i-1],height[i+1])+1爲合法長度

例如

height

0          abc

3         abcd

2         abdd

此時有效的字串是abc

#include<iostream>
#include<cstdio>
#include<cstring>
#define rint register int
#define inv inline void
#define ini inline int
#define maxn 1000050
using namespace std;
char s[maxn];
int y[maxn],x[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],wt[30];
int n,m;


inv putout(int x) {
    if(!x) {
        putchar(48);
        return;
    }
    rint l=0;
    while(x) wt[++l]=x%10,x/=10;
    while(l) putchar(wt[l--]+48);
}
inv get_SA() {
    for (rint i=1; i<=n; ++i) ++c[x[i]=s[i]];
    for (rint i=2; i<=m; ++i) c[i]+=c[i-1];
    for (rint i=n; i>=1; --i) sa[c[x[i]]--]=i;
    for (rint k=1; k<=n; k<<=1) {
        rint num=0;
        for (rint i=n-k+1; i<=n; ++i) y[++num]=i;
        for (rint i=1; i<=n; ++i) if (sa[i]>k) y[++num]=sa[i]-k;
        for (rint i=1; i<=m; ++i) c[i]=0;
        for (rint i=1; i<=n; ++i) ++c[x[i]];
        for (rint i=2; i<=m; ++i) c[i]+=c[i-1];
        for (rint i=n; i>=1; --i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
        swap(x,y);
        x[sa[1]]=1;
        num=1;
        for (rint i=2; i<=n; ++i)
            x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) ? num : ++num;
        if (num==n) break;
        m=num;
    }
}
inv get_height() {
    rint k=0;
    for (rint i=1; i<=n; ++i) rk[sa[i]]=i;
    for (rint i=1; i<=n; ++i) {
        if (rk[i]==1) continue;//第一名height爲0
        if (k) --k;//h[i]>=h[i-1]-1;
        rint j=sa[rk[i]-1];
        while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;
        height[rk[i]]=k;//h[i]=height[rk[i]];
    }
}
int belong[maxn];
int main() {
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++){
        belong[i]=1;
    }
    s[++n]=' ';
    scanf("%s",&s[n+1]);
    int st2=n+1;
    n+=strlen(&s[n+1]);
    for(int i=st2;i<=n;i++) belong[i]=2;
    m=200;
    get_SA();
    get_height();
    int mi=10000;
    for(int i=1;i<=n;i++){
        if(belong[sa[i-1]]+belong[sa[i]]==3){
            if(height[i-1]<height[i]&&height[i]>height[i+1]){
                mi=min(mi,max(height[i-1],height[i+1])+1);
            }
        }
    }
    if(mi==10000) mi=-1;
    printf("%d\n",mi);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章