P2679 [NOIP2015 提高组] 子串

题意:

给定两个串A, B。现在要从字符串 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 B 相等?

思路:

  • 状态设计:

    A串的第 i 位,匹配到了B串第 j 位,使用了k个子串。

    可以得出dp数组:f[i][j][k][u]。

  • 状态转移:

    第 i 个字符如果跟第 j 个字符相同, 则对于该字符有两种决策, 可以使用或者不使用
    1.当前使用 f[i][j][k][1] = f[i - 1][j - 1][k][1] + f[i - 1][j - 1][k - 1][0] + f[i - 1][j - 1][k - 1][0];
    2: 当前不用 f[i][j][j][0] = f[i - 1][j][k][1] + f[i - 1][j][k][0];
    第 i 个字符如果跟第 j 个字符相同, 则对于该字符只有一种决策, 不使用
    f[i][j][j][0] = f[i - 1][j][k][1] + f[i - 1][j][k][0];
    当前第i个字符不能使用 所以
    f[i][j][k][1] = 0

  • 内存优化:

    对于上述内存为 1000 * 200 * 200 * 2, 内存肯定不会爆。
    我们发现状态转移只用到了 i 和 i - 1。
    所以可以将一维优化到 2
    对于 i - 1 可以表示成 (i - 1) & 1
    对于 i 可以表示成 i & 1

代码:

  

#include <bits/stdc++.h>
#define int long long
const int MOD = 1e9 + 7;
int f[2][220][220][2];

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr), std::cout.tie(nullptr);
    int n, m, q;
    std::cin >> n >> m >> q;
    std::string a, b;
    std::cin >> a >> b;
    a = '!' + a;
    b = '!' + b;
    f[0][0][0][0] = 1;
    f[1][0][0][0] = 1;

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            for (int k = 1; k <= q; ++k) {
                if (a[i] == b[j]) {
                    f[i & 1][j][k][1] = (f[(i - 1) & 1][j - 1][k][1] + f[(i - 1) & 1][j-1][k-1][0]) + f[(i - 1) & 1][j - 1][k - 1][1];
                    f[i & 1][j][k][0] = f[(i - 1) & 1][j][k][1] + f[(i - 1) & 1][j][k][0];
                    f[i & 1][j][k][1] %= MOD;
                    f[i & 1][j][k][0] %= MOD;
                }

                else {
                    f[i & 1][j][k][0] = f[(i - 1) & 1][j][k][1] + f[(i - 1) & 1][j][k][0];
                    f[i & 1][j][k][1] = 0;
                    f[i & 1][j][k][0] %= MOD;
                }
            }
        }
    }

    std::cout << (f[n & 1][m][q][1] + f[n & 1][m][q][0]) % MOD << '\n';
    return 0;
}

 

posted @ 2022-10-25 14:51  景苌_M  阅读(56)  评论(0)    收藏  举报