CF961G Partitions

CF961G Partitions题解

题意:

给出\(n\) 个物品, 每个物品有一个权值\(w_i\)

定义一个集合\(S\) 的权值\(W(S)=|S|\sum\limits_{x\in S}w_x\)

定义一个划分的权值为\(W'(R)=\sum\limits_{S\subseteq R}W(S)\)

求将\(n\) 个物品划分成\(k\) 个集合的所有方案的权值和

\(n,k\le2\times10^5,w_i\le10^9\)

题解:

首先看出每个物品"地位"相同, 对答案的贡献肯定是\(W_i*K\)的形式, 所有的K都相等, 所以只需求出物品一的K就行

一个比较显然\((naive)\)的想法, 枚举物品一所在集合大小

\[K = \sum_{i=1}^ni * \large {\left(^{n-1}_{i-1}\right)}*\large{\left\{_{k-1}^{n-i}\right\}} \]

如果你是推式子带师, 可以一推, 但想我这样蒟蒻只能另辟蹊径

在一种划分方案中, 物品一的贡献为它所在集合大小, 相当于它对本集和中的所有点都有贡献, 它自己对自己的贡献显然是划分的方案数\(\left\{^n_k\right\}\), 对其他点的贡献相当于把剩下(n-1)个点划分, 再将其放入任意集合中, 即对所有集合中的点均有贡献, 所以答案为

\[\large{Ans = (\sum_{i=1}^nw_i)(\left\{^n_k\right\}+(n+1)\left\{^{n-1}_{~~k}\right\})} \]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int P = 1e9+7;

ll fpw(ll x, ll mi) {
	ll res = 1;
	while (mi) {
		if (mi & 1) res = res * x % P;
		x = x * x % P;
		mi >>= 1;
	}
	return res;
}

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template <typename T>
void write(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int N = 500050;
ll jie[N], inv[N];
void prework(void) {
	const int Maxn = 300000;
	jie[0] = jie[1] = inv[0] = inv[1] = 1;
	for (int i = 2;i <= Maxn; i++) 
		jie[i] = jie[i-1] * i % P, 
		inv[i] = (P - P / i) * inv[P % i] % P;
	for (int i = 2;i <= Maxn; i++) inv[i] = inv[i-1] * inv[i] % P;
}


ll strling(ll n, ll m) {
	if (m > n) return 0;
	ll ans = 0;
	for (int i = 0;i <= m; i++) {
		if ((m - i) & 1) ans -= fpw(i, n) * inv[i] % P * inv[m-i] % P;
		else ans += fpw(i, n) * inv[i] % P * inv[m-i] % P;
		ans %= P;
	}
	return (ans + P) % P;
}

ll sum;
int main() {
	prework();
	int n, k; read(n), read(k);
	for (int i = 1;i <= n; i++) {
		ll x; read(x); sum += x;
	}
	sum %= P;
	sum = sum * (strling(n, k) + (n - 1) * strling(n - 1, k) % P) % P;
	cout << sum << endl;
	return 0;
}
posted @ 2020-01-26 13:55  Hs-black  阅读(179)  评论(0编辑  收藏  举报