【CF961G】Partitions

题目

题目链接:https://codeforces.com/problemset/problem/961/G
给出 (n) 个物品,每个物品有一个权值 (w_i)
定义一个集合 (S) 的权值 (W(S)=|S|sumlimits_{xin S}w_x)
定义一个划分的权值为 (W'(R)=sumlimits_{Sin R}W(S))
求将 (n) 个物品划分成 (k) 个集合的所有方案的权值和。答案对 (10^9+7) 取模。
(n,kle2 imes10^5)(w_ile10^9)

思路

考虑每一个物品对答案的贡献。显然所有物品贡献与其权值的比值是一致的,所以我们只需要把每一个物品的权值看做 (1),最终乘上物品权值和即可。
那我们只需考虑其中一个物品的贡献即可。不难发现,该物品所在集合大小可以看做与该物品属于同一集合内的物品都会对它做 (1) 的贡献。
那么物品 (1)(egin{Bmatrix} n\ kend{Bmatrix}) 种放置方式,所以自己对自己的贡献就是 (egin{Bmatrix} n\k end{Bmatrix})
考虑其他物品对它的贡献。我们钦定物品 (1) 被放在一号集合内,因为最终集合本质相同,那么物品 (2) 就有 (frac{1}{k}egin{Bmatrix}n-1 \k end{Bmatrix}) 种方案被放在一号集合。那么总共有 (k) 个集合的情况下,这两个物品被放在同一个集合内的方案数恰好是 (egin{Bmatrix} n-1\ kend{Bmatrix})
所以答案就是

[(egin{Bmatrix} n\k end{Bmatrix}+(n-1)egin{Bmatrix} n-1\k end{Bmatrix})sum^{n}_{i=1}w_i ]

直接计算即可。
时间复杂度 (O(nlog n))

代码

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

const int N=200010,MOD=1e9+7;
int n,m;
ll ans,fac[N];

ll fpow(ll x,ll k)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%MOD)
		if (k&1) ans=ans*x%MOD;
	return ans;
}

ll sti(int n,int m)
{
	ll ans=0,p=((m&1)?-1:1);
	for (int i=0;i<=m;i++,p=-p)
		ans=(ans+fpow(i,n)*p*fpow(fac[i]*fac[m-i]%MOD,MOD-2))%MOD;
	return (ans%MOD+MOD)%MOD;
}

int main()
{
	scanf("%d%d",&n,&m);
	fac[0]=1;
	for (int i=1;i<=n;i++)
		fac[i]=fac[i-1]*i%MOD;
	ll v=(sti(n,m)+(n-1)*sti(n-1,m))%MOD;
	for (int i=1,x;i<=n;i++)
	{
		scanf("%d",&x);
		ans=(ans+v*x)%MOD;
	}
	printf("%lld",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/14301221.html