ch04 部分题目思路
G. 朋友配对
区间 dp。
设 f ( i , j ) f(i,j) f(i,j) 表示第 i 个人到第 j 个人可以两两凑对的有序方案。
递归边界应该是对于任意 i ∈ [ 1 , n + 1 ] i \in [1,n+1] i∈[1,n+1] 有 $ f(i,i-1) = 1$。
考虑对于 f ( i , j ) f(i,j) f(i,j) 的计算,决策阶段应该是枚举 i i i 和 k ∈ [ i + 1 , j ] k \in [i+1, j] k∈[i+1,j] 的哪个 k k k 配对:
- 当 i 和 k i 和 k i和k 配对,应有 ( i + 1 , k − 1 ) (i+1,k-1) (i+1,k−1) 作为一个独立的区间和 ( k + 1 , j ) (k+1,j) (k+1,j) 作为一个独立的区间,分别都能配对;
- 故有 f ( i , j ) = ∑ i < k < = j f ( i + 1 , k − 1 ) ∗ f ( k + 1 , j ) ∗ ( ( j − i + 1 ) / 2 ( k − i + 1 ) / 2 ) f(i,j) = \sum_{i<k<=j}f(i+1,k-1) * f(k+1,j) * \binom{(j-i+1)/2}{(k-i+1)/2} f(i,j)=∑i<k<=jf(i+1,k−1)∗f(k+1,j)∗((k−i+1)/2(j−i+1)/2);
- 最后面乘上的那个系数表示的是左右两部分是独立的,所以这两个的配对过程可以交错。
#include <bits/stdc++.h>
using namespace std;using ll = long long;
bool good[404][404];
ll C[202][202], f[404][404];int main() {int n, m;cin >> n >> m;for (int i = 0; i < m; ++i) {int a, b;cin >> a >> b;good[a][b] = true;}const int P = 998244353;for (int i = 0; i <= n; ++i) {C[i][0] = 1;for (int j = 1; j <= i; ++j) {C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % P;}}for (int i = 1; i <= n * 2 + 1; ++i) f[i][i - 1] = 1;for (int len = 2; len <= n * 2; len += 2) {for (int i = 1, j = i + len - 1; j <= n * 2; ++i, ++j) {for (int k = i + 1; k <= j; k += 2)if (good[i][k]) {f[i][j] += f[i + 1][k - 1] * f[k + 1][j] % P * C[(j - i + 1) / 2][(k - i + 1) / 2] % P;}f[i][j] %= P;}}cout << f[1][n * 2] << endl;return 0;
}