题解-P5546 [POI2000]公共串

题目意思

就是给你个字符串,求最长匹配的公共子串长度。

  • 二分+hash

其实这种算法是很暴力的,每次二分一个长度,然后依次去各字符串里面去匹配,如果每个串都能匹配上就二分下去就可以。然后用一个去记录这段字符串的哈希值是否出现过即可。对于一段字符串的哈希值的计算方法

这样你就拿到了的好成绩啊!

  • 正解显然是后缀自动机,然而我不会。

#include <bits/stdc++.h>

#define hash ha
#define ull unsigned long long 
using namespace std;

const int base=173;

struct IO {
    #define gc getchar
    #define pt putchar

    inline int read() {
        int sum=0,ff=1; char ch=gc();
        while(!isdigit(ch)) {
            if(ch=='-') ff=-1;
            ch=gc();
        }
        while(isdigit(ch))
            sum=sum*10+(ch^48),ch=gc();
        return sum*ff;
    }

    inline void write(int x) {
        if(x<0)
            pt('-'),x=-x;
        if(x>9)
            write(x/10);
        pt(x%10+48);
    }

    inline void writeln(int x) {
        write(x);
        pt('\n');
    }
} fast;

int n,ans,len,id;
char ch[11][2005];
ull jc[2005],hash[11][2005];
int sum[11][2005];
map<int,ull> ma[11];

inline void init() {
    jc[0]=1;
    for ( int i=1;i<=2000;i++ ) jc[i]=jc[i-1]*base;
    for ( int i=1;i<=n;i++ ) 
        for ( int j=1;j<=strlen(ch[i]+1);j++ ) 
            hash[i][j]=hash[i][j-1]*base+sum[i][j];
}

inline ull get(int now,int l,int r) {
    return hash[now][r]-hash[now][l-1]*jc[r-l+1];
}

inline bool check(int mid) {
    for ( int i=1;i<=n;i++ ) 
        ma[i].clear();
    for ( int i=1;i<n;i++ ) {
        for ( int j=1;j+mid-1<=strlen(ch[i]+1);j++ ) {
            ull tmp=get(i,j,j+mid-1);
//            cout<<tmp<<endl;
            ma[i][tmp]=1;
        }
    }
//    cout<<strlen(ch[n]+1)<<endl;
    for ( int i=1;i+mid-1<=strlen(ch[n]+1);i++ ) {
        ull tmp=get(n,i,i+mid-1);
        bool ok=false;
        for ( int j=1;j<n;j++ ) 
            if(!ma[j][tmp]) ok=true;
        if(ok==false) return true;
    }
    return false;
}


int main() {
    scanf("%d",&n);
    for ( int i=1;i<=n;i++ ) {
        scanf("%s",ch[i]+1);
        for ( int j=1;j<=strlen(ch[i]+1);j++ ) 
            sum[i][j]=ch[i][j]-'a'+1;
        if(strlen(ch[i]+1)>len) {
            len=strlen(ch[i]+1);
            id=i;
        }
    }
    init();
//    cout<<get(1,1,3)<<endl;
//    for ( int i=1;i<=n;i++ ) {
//        for ( int j=1;j<=strlen(ch[i]+1);j++ ) 
//            cout<<hash[i][j]<<" ";
//        printf("\n");
//    }
    int l=1,r=strlen(ch[id]+1);
    while(l<=r) {
        int mid=(l+r)>>1;
        if(check(mid)) {
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    fast.writeln(ans);
    return 0;
}