感觉纯结论题。
思路
首先有一个很重要的结论:
竞赛图强连通缩点后的 DAG 呈链状,前面的所有点向后面的所有点连边。
如果用强连通分量的角度来看是这样的:
一个竞赛图的 SCC 个数等于将其点集划分为两个集合 \(A, B\)(可为空集)并满足以下限制的方案数 \(-1\):
对于每条满足 \(u \in A, v \in b\) 的边 \((u, v)\),都满足其方向为 \(u \to v\)。
证明其实也很简单,利用归纳法逐一加入每个 SCC 即可。
但感觉很难在不知道的情况下想到。
知道了以后这个题就很简单。
直接 dp 即可。
时间复杂度:\(O(n^5)\)。
Code
#include <bits/stdc++.h>
using namespace std;const int mod = 998244353;int n, m, k;
int f[35][35][450];
int g[35][35][450];
int c[450][450];inline void add(int &x, int y) {if ((x += y) >= mod) x -= mod;
}int main() {cin >> n >> m, k = n * (n - 1) / 2;f[0][0][0] = 1;for (int i = 0; i <= k; i++) c[i][0] = 1;for (int i = 1; i <= k; i++)for (int j = 1; j <= k; j++)if ((c[i][j] = c[i - 1][j] + c[i - 1][j - 1]) >= mod) c[i][j] -= mod;for (int i = 1; i <= n; i++) {memset(g, 0, sizeof g);for (int l = 0; l < i; l++) {for (int r = 0; l + r < i; r++) {for (int j = 0; j <= l * r; j++) {add(g[l + 1][r][j], f[l][r][j]);add(g[l][r + 1][j + l], f[l][r][j]);}}}memcpy(f, g, sizeof f);}int ns = 0;for (int l = 0; l <= n; l++) {for (int r = 0; l + r <= n; r++) {for (int j = 0; j <= l * r; j++) {if (j <= m) ns = (ns + 1ll * c[l * (l - 1) / 2 + r * (r - 1) / 2][m - j] * g[l][r][j]) % mod;}}}cout << (ns - c[n * (n - 1) / 2][m] + mod) % mod << "\n";
}