zr1505

k = 1

(S(c) = {c_xmid xin S }), 那么答案就是:

[sum_c|S(c)| = sum_c sum_{i=1}^m[i in S(c)] ]

交换求和符号:

[sum_{i=1}^msum_c [iin S(c)] ]

这个意义就是枚举颜色 i, 然后求有多少种染色方案, 使得 i 在 (S(c)) 中, 设为 G(i)。

然后显然每种颜色是等价的, 那么 G(1) = G(2) = ... = G(m)。

所以只需要求 G(1), 取个补变成求有几种染色方案使得 1 不在 S(c) 中。

这个比较好算。


标算

相当于求 (sum_c|S(c)|^k)

根据斯特林展开公式:

[color{teal}{x^k = sum_{i=0}^k {krace i}x^{underline i} = sum_{i=0}^k {krace i}inom xi i!} ]

代入得到:

[color{orange}{sum_c} sum_{i=0}^k{krace i}color{orange}{inom {|S(c)|}i}i!\ sum_{i=0}^k{krace i}i! color{orange}{sum_cinom {|S(c)|}i} ]

剩下的就是求 (g(i) = sum_c inom{|S(c)|}i), 等价于:枚举所有大小为 i 的颜色集合 t, 并算出有多少 c 满足 (t subseteq S(c))

令 h(i) 为:对于某个大小为 i 的颜色集合 T, 有几个 c 满足 (t subseteq S(c))

那么 (g(i) = inom mi h(i))

对于 (h(i)), 考虑用容斥原理去算, 每次枚举有 j 个 T 中的颜色不在 S(c) 中, 令 dp(j) 表示对于一个大小为 j 的颜色集合 Ban, 有几个 c 满足 (Bancap S(c) = varnothing), 有:

[h(i) = sum_{j=0}^i (-1)^jinom ijdp(j) ]

对于 dp(j), 可以直接树形 dp。

那么算法的流程就是:

对于 0...k,预处理出 dp(j)。

然后计算即可。

总复杂度 (O(nk+k^2))

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;

const int N = 1e5 + 23, K = 93, mo = 998244353;

int n, m, k, _S_, S[N];
bool vis[N];
LL c[K][K], s[K][K];

int ecnt, hd[N], nt[N*2+1], vr[N*2+1];
void ad (int x, int y) { nt[++ ecnt] = hd[x], hd[x] = ecnt, vr[ecnt] = y; }

LL f[N][2], dp[K];
void dfs (int x, int F, int j) {
	f[x][0] = 1ll, f[x][1] = vis[x] ? 0ll : 1ll;
	for (int i = hd[x]; i; i = nt[i]) {
		int y = vr[i];
		if (y == F) continue;
		dfs (y, x, j);
		f[x][0] *= ((LL)(m - j - 1) * f[y][0] % mo + (LL)j * f[y][1] % mo) % mo, f[x][0] %= mo;
		f[x][1] *= ((LL)(m - j) * f[y][0] % mo + (LL)(j - 1) * f[y][1] % mo) % mo, f[x][1] %= mo;
	}
}

int main()
{
	scanf ("%d%d%d%d", & n, & m, & k, & _S_);
	for (int i = 1; i <= _S_; ++ i) scanf ("%d", & S[i]), vis[S[i]] = true;
	for (int i = 1, x, y; i < n; ++ i) scanf("%d%d", & x, & y), ad (x, y), ad (y, x);
	c[0][0] = s[0][0] = 1ll;
	for (int i = 1; i <= k; ++ i) {
		c[i][0] = 1ll;
		for (int j = 1; j <= i; ++ j) {
			c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mo;
			s[i][j] = (s[i - 1][j] * (LL)j + s[i - 1][j - 1] ) % mo;
		}
	}
	for (int i = 0; i <= k; ++ i)
		dfs (1, 0, i), dp[i] = ((LL)(m - i) * f[1][0] % mo + (LL)i * f[1][1] % mo) % mo;
	LL ans = 0ll, faci = 1ll;
	for (int i = 0; i <= k; ++ i) {
		LL now = 0ll;
		for (int j = 0; j <= i; ++ j)
			now = (now + (j&1 ? -1ll : 1ll) * c[i][j] * dp[j] % mo) % mo;
		ans += now * faci % mo * s[k][i] % mo;
		ans %= mo;
		faci = faci * (LL)(m - i) % mo;
	}
	cout << (ans % mo + mo) % mo;
	return 0;
}
原文地址:https://www.cnblogs.com/tztqwq/p/14490782.html