GYM 101933K(二項式反演、排列組合)
阿新 • • 發佈:2019-05-12
scan mod 二項式 意義 clu std 使用 %d 排列
要點
- 設\(f_i\)為最多使用\(i\)種顏色的塗色方案,\(g_i\)為恰好只使用\(i\)種顏色的塗色方案。可知此題答案為\(g_k\)。
- 根據排列組合的知識不難得到\(f_k = \sum_{i=0}^k{C_k^i*g_i}\)。
- 根據二項式反演的式子 or 容斥原理,有\(g_k = \sum_{i = 0}^k{(-1)^{k-i}*C_k^i*f_i}\),這時只要有\(f_i\)我們就可以累加得到最終答案,看題面考慮\(f_i\)的現實意義,根有\(i\)種可選,往下塗每個點有\(i-1\)種可選(因為是樹形的,所以子節點塗色只要和父親不同即可),故\(f_i = i * (i - 1)^{n - 1}\)
#include <cstdio> const int mod = 1e9 + 7; int n, k, ans; int C[2505][2505], f[2505]; int ksm(int a, int b) { int res = 1; for (; b; b >>= 1) { if (b & 1) res = 1LL * res * a % mod; a = 1LL * a * a % mod; } return res; } void Pre() { for (int i = 0; i <= k; i++) { f[i] = 1LL * i * ksm(i - 1, n - 1) % mod; C[i][i] = C[i][0] = 1; for (int j = 1; j < i; j++) { C[i][j] = (1LL * C[i - 1][j] + C[i - 1][j - 1]) % mod; } } } int main() { scanf("%d %d", &n, &k); for (int i = 1, x; i < n; i++) scanf("%d", &x); Pre(); for (int i = 0; i <= k; i++) { int a = (k - i) % 2 ? -1 : 1; int tmp = (1LL * a * C[k][i] % mod * f[i] % mod + mod) % mod; ans = (ans + tmp) % mod; } return !printf("%d\n", ans); }
GYM 101933K(二項式反演、排列組合)