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; }
标签:dp2,P7914,笔记,len,dpb,dpa,505,mod From: https://www.cnblogs.com/Xy-top/p/17768251.html