题解

cookiebus 2023-08-09 8:40:42 2024-01-31 16:04:02 5 返回题目

下文 均表示

先考虑一个文件、一个通配字符子串,怎么判断合法的方案数。

定义 表示已经考虑完了字符串中的前 个点,目前将所有*替换之后匹配了目标文件前 个字符的方案数。

转移显然:当 为字母,若文件第 字符与 相等,则

如果 为 *,则

单个时间复杂度 (暴力转移)或 (前缀和优化),总体时间复杂度

我们考虑将所有子串的贡献统一处理。

定义 表示已经考虑完了字符串中的前 个点,目前将所有*替换之后匹配了目标文件前 个字符的方案数总和。

那么转移变成:当 为字母,若文件第 字符与 相等,则

如果 为*,则 则 最后,令 (新增一个子串开头)。

最后, 。意为枚举子串右端点。

对于每一个文件求解即可。时间复杂度 。经前缀和优化可做到

#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5, M = 1000 + 5, P = 998244853;
char c[N], s[M][M];
int len[N];
int n, m;
namespace sub5 {
long long dp[N][M];
void solve() {
    long long ans = 0;
    for (int k = 1; k <= m; k++) {
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= len[k]; j++) {
                if (c[i] == s[k][j] || c[i] == '*')
                    dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % P;
                if (c[i] == '*')
                    dp[i][j] = (dp[i][j] + dp[i][j - 1]) % P;
            }
            if (c[i] == '*')
                for (int j = 0; j <= len[k]; j++) dp[i][j] = (dp[i][j] + dp[i - 1][j]) % P;
            dp[i][0]++;
            ans = (ans + dp[i][len[k]]) % P;
            // cout << ans << " " << k << " " << i << endl;
        }
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= len[k]; j++) dp[i][j] = 0;
    }
    printf("%lld", ans);
}
}  // namespace sub5
int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", c + 1);
    for (int i = 1; i <= m; i++) {
        scanf("%s", s[i] + 1);
        len[i] = strlen(s[i] + 1);
    }
    sub5::solve();
    return 0;
}
{{ vote && vote.total.up }}

共 1 条回复

xieyikai1112

取模(笑)