HDU 6661Acesrc and String Theory (多校第八场) 字符串hash

http://acm.hdu.edu.cn/showproblem.php?pid=6661

多校被虐得自闭,我还是太菜了

题意:很简单,就是问你有多个子串,能过被分割成相等的k个子串部分,不能有重复,比如aa可以分成两个a,ababab这能分成三个ab。

做法:首先想怎么做,肯定子串的长度是k的整数倍,我们枚举长度显然是不合理的。

我们换一种思路,枚举一个长度len的整数倍,判断有多少个子串以len为周期循环,那么就可以轻松得出答案了。

比如我们看看题解上的那个样例 s=abcabcabdabd 对于len=3有两个这样的子串 abcabcab,他的循环节是3,他的长度是8因此容易得出答案的贡献就是 8-3*k+1,当然要大于零才加上,这个如果对于k=2,就有三个abcabc bcabca cabcab,第二个字符串abdabd只有一个了。这样我们枚举一个x然后判断连续的x段是否相等,就可以了,如果有相邻不相等,我们要求得相邻两段它们的公共前缀的LCP,然后再求判断,对于答案有没有贡献(本题重点就是求这个)。同时关于下一端的起点我们要通过它们的公共后缀的LCP来判断,比如aabbabb,当长度枚举到3时,首先时aab和bab不相同,然后显然我们下次枚举的线段应该是abb和abb这个就是公共后缀有关了。如果没清楚自己yy一下吧,还不清楚欢迎下面评论。

标程是后缀数组,哎,写不来了,看也没有看懂。。。。。

就随便写了一个hash,hash二分求前后缀的LCP

因为复杂度的是O(n+\frac{n}{2}+\frac{n}{3}+....)=O(nlogn).再加上一个hash二分,最多多算一个logn,考虑最坏的情况每一次都要判断前后缀的LCP,但不过这个logn无视,一秒钟稳稳的。

#include "bits/stdc++.h"

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1000000 + 10;
///const ull base = 201326611;
const ull base = 131;
char str[N];
int k;
ull ha[N], p[N];
ull getha(int l, int r) {
    if (l == 0) return ha[r];
    return ha[r] - ha[l - 1] * p[r - l + 1];
}

int pre_check(int l, int ql, int len) {
    int L = 0, R = len;
    int mid, ret;
    while (L <= R) {
        mid = (L + R) >> 1;
        if (getha(l, l + mid - 1) == getha(ql, ql + mid - 1)) {
            ret = mid;
            L = mid + 1;
        } else R = mid - 1;
    }
    return ret;
}

int suffix_check(int r, int qr, int len) {
    int L = 0, R = len;
    int mid, ret;
    while (L <= R) {
        mid = (L + R) >> 1;
        if (getha(r - mid + 1, r) == getha(qr - mid + 1, qr)) {
            ret = mid;
            L = mid + 1;
        } else R = mid - 1;
    }
    return ret;
}

void solve(int len) {
    ll ans = 0;
    for (int x = 1; x <= len; x++) {
        int cnt = 0, i = 0;
        ull last = 0, tmp;
        int t = x;
        while (i < len) {
            if (i + t - 1 >= len) t = len - i;
            tmp = getha(i, i + t - 1);
            if (last == 0) {
                last = tmp, cnt = 1, i += x;
                continue;
            }
            if (last == tmp) {
                cnt++;
                i += x;
            } else {
                ll l1 = pre_check(i - x, i, t);
                ll l2 = suffix_check(i + t - 1, i - 1, t);
                ll l = cnt * x + l1;
                if (l >= k * x) ans += l - k * x + 1;
                i += x - l2;
                last = getha(i - x, i - 1), cnt = 1;
            }
        }
        if (cnt >= k) {
            ll l1 = pre_check(i - x, i, t);
            ll l = cnt * x + l1;
            if (l >= k * x) ans += l - k * x + 1;
        }
    }
    printf("%lld\n", ans);
}

int main() {
    p[0] = 1;
    for (int i = 1; i < N; i++) p[i] = p[i - 1] * base;
    int T;
    cin >> T;
    while (T--) {
        cin >> k >> str;
        int len = strlen(str);
        if (k == 1) {
            printf("%lld\n", 1ll * len * (len + 1) / 2);
            continue;
        }
        ha[0] = (ull) str[0];
        for (int i = 1; i < len; i++)
            ha[i] = ha[i - 1] * base + str[i];
        solve(len);
    }
    return 0;
}

发布了130 篇原创文章 · 获赞 80 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/99621259
今日推荐