「COCI2019-2020#5」 Zapina 题解

「COCI2019-2020#5」 Zapina 题解

题意

\(n\) 个人和 \(n\) 道题,现在把每个题给人,至少有一个下标为 \(i\) 的人得到 \(i\) 道题, 问分配的方案数量

考虑用所有的方案数减去不开心的方案数。

所有的方案数就是 \(n^n\)

不开心的方案数用 DP 解决, 用 \(f_{i,j}\) 表示前 \(i\) 个人 \(j\) 道题目不开心的数量。

用三重循环做这个题,即 \(i, j, k\)

表示分配到第 \(i\) 个人,前 \(j\) 道题里面给了这个人 \(k\) 道题。

先假设题目都是一样的, 就有这样的状态转移方程

\[f_{i, j} = f_{i, j} + f_{i - 1, j - k} \]

第二部分表示上一步的状态,即分配到了 \(i-1\)个人,已经分配了 \(j-k\) 道题的状态。

在这里题目都是不一样的,所以这个选择题目要乘上一个\(C(j,k)\), 表示在 \(j\) 里面选择 \(k\) 个题。

Code

#include <bits/stdc++.h>

using i64 = long long;
constexpr i64 N = 400;
constexpr i64 md = 1e9 + 7;

inline i64 q_pow(i64 a, i64 b) {
	i64 ans = 1;
	while (b) {
		if (b & 1) ans = (ans * a) % md;
		a = (a * a) % md;
		b >>= 1;
	}
	return ans % md;
} 
i64 f[N + 1][N + 1];
i64 dp[N + 1][N + 1];
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);std::cout.tie(0);
	
	i64 n;
	std::cin >> n;
	
	f[0][0] = f[1][0] = f[1][1] = 1;
	for (i64 i = 2; i <= n; i++) {
		f[i][0] = 1;
	}
	for (i64 i = 2; i <= n; i++) {
		for (i64 j = 1; j <= n; j++) {
			f[i][j] = (f[i - 1][j - 1] + f[i - 1][j]) % md;
		}
	}
	
	dp[0][0] = 1;
	for (i64 i = 1; i <= n; i++) {	
		for (i64 j = 0; j <= n; j++) {
			for (i64 k = 0; k <= j; k++) {
				if (k != i)
					dp[i][j] = (dp[i][j] + dp[i - 1][j - k] * f[j][k]) % md;
			}
		}	
	}
	
	i64 ans = (q_pow(n, n) % md - dp[n][n] + md) % md;
	std::cout << ans % md << std::endl;

		
	return 0;
}
posted @ 2022-02-09 19:27  落花月朦胧  阅读(169)  评论(0编辑  收藏  举报