牛客IOI周赛23-提高组 A-单词

单词

https://ac.nowcoder.com/acm/contest/11165/A

先用kmp求出t能出现在s的哪些位置。
我们维护这样的三个dp方程:
dp1[i]表示 最后一个区间结尾r在i的方案数。
dp2[i]表示 最后一个区间结尾r在[0...i]的方案数。
dp3[i]表示 最后一个区间开头l在[0...i]的方案数。
转移即可,dp2[n]即为答案。
复杂度O(n)。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

typedef long long ll;

const int N = 1e6 + 100;
const int MOD = 99824353;

int n, m;
int nex[N];
char s1[N], s2[N];

void getnex(char *str, int n) {
    int i = 0, j = -1;
    nex[0] = -1;
    while (i < n) {
        if (j == -1 || str[i] == str[j]) {
            i++; j++;
            nex[i] = j;
        }
        else
            j = nex[j];
    }
}

vector<int> V;
int dp1[N], dp2[N], dp3[N];

/*
dp1[i] 表示r以i结尾的区间个数
dp2[i] 表示r以0...i结尾的区间个数
dp3[i] 表示l在0...i的区间个数
*/

void upd(int &a, int b) {
    a += b;
    if (a >= MOD) a -= MOD;
}

int main() {
    //freopen("0.txt", "r", stdin);
    scanf("%s%s", s1, s2);
    n = strlen(s1);
    m = strlen(s2);
    getnex(s2, m);
    for (int i = 0, j = 0; i < n;) {
        if (j == -1 || s1[i] == s2[j]) {
            i++; j++;
            if (j == m) V.push_back(i);
        }
        else
            j = nex[j];
    }
    if (V.size() == 0) { puts("1"); return 0; }
    dp1[0] = dp2[0] = 1;
    int ans = 0;
    for (int i = 1, j = 0; i <= n; i++) {
        dp3[i] = (dp3[i - 1] + dp2[i - 1]) % MOD;
        if (i >= V[0]) {
            if (j + 1 < V.size() && i == V[j + 1]) j++;
            dp1[i] = dp3[V[j] - m + 1];
        }
        dp2[i] = (dp2[i - 1] + dp1[i]) % MOD;
    }
    printf("%d\n", dp2[n]);
    return 0;
}
全部评论

相关推荐

双非一本失业第二年:《机器视觉垃圾分类》
点赞 评论 收藏
分享
评论
5
收藏
分享
牛客网
牛客企业服务