P7914 做题笔记

题目链接

CSP 考前做下历年真题。

转移很多,我刚开始设 $dp1[i][j]$ 为 $i$ 到 $j$ 合法的方案数,$dp2[i][j]$ 为左边一段 $*$,右边是合法的方案数,以及 $dp3[i][j]$,右边是 $*$,左边合法。

然后就进坑了,比如 $()()()$,会在第二个位置统计一下,(两个合法的字符串拼起来)也会在第四个位置统计一下,苦思冥想了 $1$ 分钟,得出解决方案:将 $dp1[i][j]$ 拆成两个分别是 $dpa[i][j]$ 和 $dpb[i][j]$,前者表示最外部是一个互相匹配的括号,后者表示的是符合的,但左右不是配对的方案数。

转移略有些复杂。

#include <bits/stdc++.h>
#define int long long
#define For(i, a, b) for (int i = (a); i <= (b); i ++)
#define foR(i, a, b) for (int i = (a); i >= (b); i --)
using namespace std;
int n, k;
int dp2[505][505], dp3[505][505];
int dpa[505][505], dpb[505][505];
//dpa[i][j]:[i, j] 合法方案数,且字符串两侧是配对的 '(' ')'
//dpb[i][j]:[i, j] 合法方案数,且字符串两侧不是配对的 '(' ')'
bool c[505][505];
char s[505];
const int mod = 1000000007;
bool check (char a, char b) {
    if (a == b || a == '?') return 1;
    return 0;
}
void solve () {
    scanf ("%d%d%s", &n, &k, s + 1);
    For (i, 1, n)
        if (s[i] == '?' || s[i] == '*') c[i][i] = 1;
    For (i, 1, n) c[i][i - 1] = 1;
    For (len, 2, n) {
        For (i, 1, n - len + 1) {
            int j = i + len - 1;
            c[i][j] = (c[i][i] && c[i + 1][j]);
        }
    }
    For (len, 2, n) {
        For (i, 1, n - len + 1) {
            int j = i + len - 1;
            //dp2[i][j]:左边若干个 *,右边是符合要求的
            //dp3[i][j]:右边若干个 *,左边是符合要求的
            For (l, 1, min (len - 1, k) ) {
                if (c[i][i + l - 1]) {
                    dp2[i][j] = dp2[i][j] + (dpa[i + l][j] + dpb[i + l][j]) % mod;
                    if (dp2[i][j] >= mod) dp2[i][j] -= mod;
                }
                if (c[j - l + 1][j]) {
                    dp3[i][j] = dp3[i][j] + (dpa[i][j - l] + dpb[i][j - l]) % mod;
                    if (dp3[i][j] >= mod) dp3[i][j] -= mod;
                }
            }
            //dp1[i][j]:区间 [i, j] 中符合要求的括号序列的数量
            if (c[i + 1][j - 1] && check (s[i], '(') && check (s[j], ')') && len - 2 <= k) dpa[i][j] = 1;
            For (l, i, j - 1) {
                dpb[i][j] = dpb[i][j] + dpa[i][l] * dpa[l + 1][j] % mod;
                if (dpb[i][j] >= mod) dpb[i][j] -= mod;
                dpb[i][j] = dpb[i][j] + dpa[i][l] * dpb[l + 1][j] % mod;
                if (dpb[i][j] >= mod) dpb[i][j] -= mod;
            }
            if (check (s[i], '(') && check (s[j], ')') )
                dpa[i][j] = (dpa[i][j] + dpa[i + 1][j - 1] + dpb[i + 1][j - 1] + dp2[i + 1][j - 1] + dp3[i + 1][j - 1]) % mod;
            For (l, 1, j - 1) {
                dpb[i][j] = (dpb[i][j] + (dpa[i][l] * dp2[l + 1][j]) % mod) % mod;
                if (dpb[i][j] >= mod) dpb[i][j] -= mod;
            }
        }
    }
    cout << (dpa[1][n] + dpb[1][n]) % mod;
}
signed main () {
    int _ = 1;
//    cin >> _;
    while (_ --) {
        solve ();
        cout << '\n';
    }
    return 0;
}

 

posted @ 2023-10-16 20:11  Xy_top  阅读(8)  评论(0编辑  收藏  举报