bzoj 3670 [Noi2014]动物园 KMP

题面

题目传送门

解法

感觉自己以前从来没学过KMP……不知道学得什么东西

  • 既然题目里面已经明确要求使用KMP了,那就KMP了
  • c n t [ i ] 表示字符串以 i 结尾的前缀中前缀等于后缀的字符串个数(包括自己)
  • 可以发现, c n t 可以在求解 n x t 的时候计算出来,即 c n t [ i ] = c n t [ n x t [ i ] ] + 1
  • 这样,我们就得到了一个弱化版的 n u m 数组
  • 考虑 n u m 数组怎么求,其实我们没有必要每一次都花 O ( l o g ) 的时间求出不大于这个前缀长度一半的位置,可以直接借用上一次的位置继续做,和KMP算法在匹配字符串的过程中类似
    • 时间复杂度: O ( T n )

代码

#include <bits/stdc++.h>
#define Mod 1000000007
#define N 1000010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
char st[N];
int nxt[N], cnt[N];
int main() {
    int T; read(T);
    while (T--) {
        scanf(" %s", st + 1);
        int l = strlen(st + 1);
        nxt[1] = 0, cnt[1] = 1;
        for (int i = 2; i <= l; i++) {
            int j = nxt[i - 1];
            while (j && st[i] != st[j + 1]) j = nxt[j];
            if (st[i] == st[j + 1]) j++;
            nxt[i] = j, cnt[i] = cnt[nxt[i]] + 1;
        }
        int ans = 1, j = 0;
        for (int i = 2; i <= l; i++) {
            while (j && st[j + 1] != st[i]) j = nxt[j];
            if (st[i] == st[j + 1]) j++;
            while (j * 2 > i) j = nxt[j];
            ans = 1ll * (cnt[j] + 1) * ans % Mod;
        }
        cout << ans << "\n";
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/emmmmmmmmm/article/details/82081456