給定
一個序列合法,當且僅當編號 ≤
轉移方程:
f[i][j] = Σ f[i-1][j-k] * C(sum[i] - cnt[i] - (j-k), k - cnt[i])
k = cnt[i] ... j-i+1
其中組合數表示:從剩餘
#include <cstdio>
#include <cstring>
#include <iostream>
#define M 330
using namespace std;
int n, m, p;
int cnt[M], sum[M];
long long C[M][M], f[M][M];
void Initialize() {
memset(cnt, 0, sizeof cnt);
memset(C, 0, sizeof C);
memset(f, 0, sizeof f);
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] + C[i-1][j-1]) % p;
}
}
int main() {
int T;
cin >> T;
while (T--) {
cin >> n >> m >> p;
sum[0] = n - m;
Initialize();
for (int i = 1; i <= m; i++) {
int x; scanf("%*d%d", &x);
cnt[x]++;
}
for (int i = 1; i <= n; i++) {
sum[i] = sum[i-1] + cnt[i];
if (sum[i] < i) { /* 不合法,可提前結束 */ }
}
for (int i = 1; i <= n; i++)
for (int j = sum[i]; j >= i; j--)
for (int k = j - i + 1; k >= cnt[i]; k--)
(f[i][j] += f[i-1][j-k] * C[sum[i] - j + k - cnt[i]][k - cnt[i]]) %= p;
printf("%d\n", (int)f[n][n]);
}
return 0;
}