POJ 2774 Long Long Message (二分 + Hash 求最长公共子串)题解

题意:求最长公共子串

思路:把两个串Hash,然后我们把短的作为LCS的最大可能值,然后二分长度,每次判断这样二分可不可以。判断时,先拿出第一个母串所有len长的子串,排序,然后枚举第二个母串len长度字串,二分查找在第一个母串的子串中存不存在。

代码:

#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 100000 + 10;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
ull hs[maxn], hp[maxn], fac[maxn], q[maxn];
int len1, len2;
char s[maxn], p[maxn];
ull get_hash(ull *h, int l, int r){
    return h[r] - h[l - 1] * fac[r - l + 1];
}
bool check(int len){
    int cnt = 0;
    for(int i = 1; i + len - 1 <= len1; i++){
        q[cnt++] = get_hash(hs, i, i + len - 1);
    }
    sort(q, q + cnt);
    for(int i = 1; i + len - 1 <= len2; i++){
        ull aim = get_hash(hp, i, i + len - 1);
        if(binary_search(q, q + cnt, aim)) return true;
    }
    return false;
}
int main(){
    fac[0] = 1;
    for(int i = 1; i < maxn; i++)
        fac[i] = fac[i - 1] * seed;
    while(~scanf("%s%s", s + 1, p + 1)){
        len1 = strlen(s + 1);
        len2 = strlen(p + 1);
        hs[0] = hp[0] = 0;
        for(int i = 1; i <= len1; i++)
            hs[i] = hs[i - 1] * seed + (s[i] - 'a');
        for(int i = 1; i <= len2; i++)
            hp[i] = hp[i - 1] * seed + (p[i] - 'a');
        int l = 0, r = min(len1, len2);
        int ans = 0;
        while(l <= r){
            int m = (l + r) >> 1;
            if(check(m)){
                l = m + 1;
                ans = m;
            }
            else{
                r = m - 1;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/KirinSB/p/10662817.html
今日推荐