算法进阶指南---0x18(二分+hash)匹配统计

原题链接

在这里插入图片描述

题解

  1. 此题可以用KMP写,也可以用hash写(简单),我们先用hash写
  1. 我们先预处理出A和B的hash,然后枚举A的后缀字串所能匹配的B的最大长度,统计长度即可
  1. 对于A的每个后缀字串,我们可以用二分来求所能匹配的最大长度

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>


using namespace std;
typedef unsigned long long ULL;
const int P = 131;
const int N = 2e5 + 10;

int n, m, q, x;
char a[N], b[N];
int pa[N], pb[N], ha[N], hb[N];
int cnt[N];

ULL get(char c, int l, int r) {
    
    
    if (c == 'a') {
    
    
        return ha[r] - ha[l - 1] * pa[r - l + 1];
    } else {
    
    
        return hb[r] - hb[l - 1] * pb[r - l + 1];
    }
}

int main() {
    
    

    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    cin >> n >> m >> q;
    cin >> a + 1 >> b + 1;

    //预处理hash
    pa[0] = 1;
    for (int i = 1; i <= n; i++) {
    
    
        ha[i] = ha[i - 1] * P + a[i];
        pa[i] = pa[i - 1] * P;
    }
    pb[0] = 1;
    for (int i = 1; i <= m; i++) {
    
    
        hb[i] = hb[i - 1] * P + b[i];
        pb[i] = pb[i - 1] * P;
    }

    //二分求匹配的最大长度
    for (int i = 1; i <= n; i++) {
    
    

        int l = 0, r = min(n - i + 1, m);
        while (l < r) {
    
    
            int mid = (l + r) >> 1;
            if (get('a', i, i + mid) == get('b', 1, 1 + mid)) l = mid+1;
            else r=mid;
        }
        cnt[l]++;
    }
    
    while (q--) {
    
    
        cin >> x;
        cout << cnt[x] << endl;
    }


    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44791484/article/details/114288323