HDU 4821 字符串哈希

題意:

給出m和L和一個字符串s,要求在s中找到一種子串,滿足長度爲m*l,且分成m段長度爲l的小子串可以使得任意兩個小子串不完全相同,問一共有多少個這樣的子串。


思路:

字符串哈希。
預處理出每個長度爲L的子串的哈希值,並按照其起始位置%L的結果存在L個vector裏,對於每個vector只要單純看連續m個數是否有相同的數字即可,如果沒有就更新答案。


代碼:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const ULL seed = 131;
const int MAXN = 1e5 + 10;

int m, l;
char s[MAXN];
ULL sum[MAXN], f[MAXN];
vector <ULL> vec[MAXN];

void init() {
    f[0] = 1;
    for (int i = 1; i <= 100000; i++)
        f[i] = f[i - 1] * seed;
}

int cal() {
    int ans = 0;
    for (int i = 0; i < l; i++) {
        int cnt = 0;
        if ((int)vec[i].size() < m) continue;
        map <ULL, int> mp;
        for (int j = 0; j < m; j++) {
            if (mp[vec[i][j]] == 1) ++cnt;
            ++mp[vec[i][j]];
        }
        if (cnt == 0) ++ans;
        for (int j = 1; j + m <= (int)vec[i].size(); j++) {
            --mp[vec[i][j - 1]];
            if (mp[vec[i][j - 1]] == 1) --cnt;
            if (mp[vec[i][j + m - 1]] == 1) ++cnt;
            ++mp[vec[i][j + m - 1]];
            if (cnt == 0) ++ans;
        }
    }
    return ans;
}

int main() {
    //freopen("in.txt", "r", stdin);
    init();
    while (scanf("%d%d", &m, &l) == 2) {
        scanf("%s", s + 1);
        int len = strlen(s + 1);
        for (int i = 1; i <= len; i++) {
            sum[i] = sum[i - 1] * seed + s[i] - 'a';
        }
        for (int i = 0; i < l; i++) vec[i].clear();
        for (int i = 1; i + l - 1 <= len; i++) {
            int j = i + l - 1;
            ULL tmp = sum[j] - sum[i - 1] * f[j - i + 1];
            vec[(i - 1) % l].push_back(tmp);
        }
        printf("%d\n", cal());
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章