CF961G Partitions

题意

link
求将 n 个物品划分成 k 个集合的所有方案的权值和,权值和为每个集合的大小乘集合元素的和的和。

推式子就完了

一眼得:

\[\sum_{x = 1}^nw_x \sum_{i = 1}^{n}i\binom{n - 1}{i - 1} \begin{Bmatrix} n - i\\ k - 1\end{Bmatrix} \]

和是线性的,直接拆开算每个元素贡献,枚举它所在集合的大小 \(i\),给它选 \(i - 1\) 个数,剩下 \(n - i\) 个数自己分成 \(k - 1\) 个非空集合。

考虑拆开第二类斯特林数,有个容斥的式子:

\[\begin{Bmatrix} n\\ m \end{Bmatrix} = \frac{1}{m!} \sum_{i = 0}^{m} (-1)^i(m - i)^n\binom{m}{i} \]

\[= \sum_{i = 0}^{m} \frac{(-1)^i(m - i)^n}{i!(m - i)!} \]

实际上只要计算出后面的式子:

\[\sum_{i = 1}^{n}i\binom{n - 1}{i - 1} \sum_{j = 0}^{k - 1} \frac{(-1)^j(k - 1 - j)^{n - i}}{j!(k - 1 - j)!} \]

后面的拆开的式子又不能合回去,那就把它移到前面:

\[\sum_{j = 0}^{k - 1} \frac{(-1)^j}{j!(k - 1 - j)!}\sum_{i = 1}^{n}i\binom{n - 1}{i - 1}(k - 1 - j)^{n - i} \]

发现 \(n - i\)\(i - 1\) 等于 \(n - 1\), 但是多了 \(i\),要不然就能用二项式定理了,那就拆开,令 \(i = 1 + (i - 1)\)

\[\sum_{j = 0}^{k - 1} \frac{(-1)^j}{j!(k - 1 - j)!}(\sum_{i = 1}^{n}\binom{n - 1}{i - 1}(k - 1 - j)^{n - i} + \sum_{i = 1}^{n}(i - 1)\binom{n - 1}{i - 1}(k - 1 - j)^{n - i}) \]

那么:

\[\sum_{i = 1}^{n}\binom{n - 1}{i - 1}(k - 1 - j)^{n - i} = (k - 1 - j + 1) ^ {n - 1} \]

注意到 \((i - 1)\)\(\binom{n - 1}{i - 1}\), 有这样一个组合恒等式:

\[m \binom{n}{m} = \frac{(n - 1)! n}{(m - 1)! (n - m)!} = n \binom{n - 1}{m - 1} \]

利用这个式子,可以把一个变量替换成不变量,是推组合式子的常用操作。

就有:

\[\sum_{i = 1}^{n}(i - 1)\binom{n - 1}{i - 1}(k - 1 - j)^{n - i}) = \sum_{i = 1}^{n}(n - 1)\binom{n - 2}{i - 2}(k - 1 - j)^{n - i} \]

再提出 \(n - 1\):

\[(n - 1)\sum_{i = 1}^{n - 2}\binom{n - 2}{i - 2}(k - 1 - j)^{n - i} \]

利用二项式定理,就有:

\[(n - 1)(k - 1 - j + 1)^{n - 2} \]

因此,上面的式子为:

\[\sum_{j = 0}^{k - 1} \frac{(-1)^j}{j!(k - 1 - j)!}[(k - j) ^ {n - 1} + (n - 1)(k - j)^{n - 2}] \]

在时间复杂度 \(O(n \log n)\) 就能算出。

不然就得用 MTT 计算第二类斯特林数的生成函数,时间复杂度是大常数 \(O(n \log^2 n)\), 码量爆炸。

代码

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

using ll = long long;
const int MAXN = 200010;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-9; 

template <typename T>
void Read(T &x) {
	x = 0; T f = 1; char a = getchar();
	for(; a < '0' || '9' < a; a = getchar()) if (a == '-') f = -f;
	for(; '0' <= a && a <= '9'; a = getchar()) x = (x * 10) + (a ^ 48);
	x *= f;
}

inline int add(const int &a, const int &b, const int p = mod) {
	static int c;
	c = a + b;
	if (c >= p) c -= p;
	return c; 
} 
inline int dec(const int &a, const int &b, const int p = mod) {
	static int c;
	c = a - b;
	if (c < 0) c += p;
	return c; 
} 
inline int mul(const int &a, const int &b, const int p = mod) {
	return 1ll * a * b % p; 
}
inline int qpow(int a, int b, const int p = mod) {
	int sum(1);
	while(b) {
		if (b & 1) sum = mul(sum, a, p);
		a = mul(a, a, p);
		b >>= 1; 
	}
	return sum; 
}

int n, k; 
 
int f[MAXN], ifa[MAXN]; 
int main() {
	Read(n); Read(k);
	if (n == 1) {
		int w;
		Read(w);
		return cout << w, 0 ; 
	}
	f[0] = 1; 
	for (int i = 1; i <= k - 1; i ++)	
		f[i] = mul(f[i - 1], i);
	ifa[k - 1] = qpow(f[k - 1], mod - 2);
	for (int i = k - 2; i >= 0; i --)
		ifa[i] = mul(ifa[i + 1], i + 1);
	int sum = 0;
	for (int i = 0, p = 1; i <= k - 1; i ++, p = mod - p) 
		sum = add(sum, mul(mul(mul(p, ifa[i]), ifa[k - 1 - i]), add(qpow(k - i, n - 1), mul(n - 1, qpow(k - i, n - 2))))); 
	int ans = 0; 
	for (int i = 1; i <= n; i ++) {
		int w; 
		Read(w);
		ans = add(ans, mul(w, sum));  
	}
	cout << ans; 
	
	return 0;	
} 
posted @ 2022-03-07 20:27  qjbqjb  阅读(23)  评论(0编辑  收藏  举报