Codeforces 961G Partitions [第二类斯特林数+想法]

题意:给你长度为n的数列,要将其划分为k个集合,一个集合的贡献为W(S)=sum(wi)*size,一种划分的贡献为W(R)=sum(W(S))。求所有划分的贡献和。

题解:首先我们可以简单得知,答案是cfi*(sum(wi))(cif是系数),然后我们考虑系数的计算,对于第i个数,假如第j个数与第i个数在一组的话,那么贡献加一,所以我们只需要计算i与j在一组的情况的总和s,如何计算s呢,首先我们将j这个数单独拿出来,然后对剩下n-1个数,算出从中划分出k个无序集合的方案数(也就是第二类斯特林数S(n-1,k)),然后将j与i放在一组就可以了,所有当i与j不同时,贡献为(n-1)S(n-1,k),当i==j的时候贡献为S(n,k),所有总的贡献为S(n,k)+(n-1)*S(n-1,k)。

所以答案就是sum(wi)*(S(n,k)+(n-1)*S(n-1,k))。

第二类斯特林数内容可以查看博客:https://blog.csdn.net/acterminate/article/details/77336649

AC代码:

#include<stdio.h>
#define mod 1000000007 
typedef long long ll;
ll inv[200005],f[200005],jie[200005];
ll qmi(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b%2)ans=ans*a%mod;
		a=a*a%mod;
		b/=2;
	}
	return ans;
}
ll C(ll x,ll y){return jie[x]*f[y]%mod*f[x-y]%mod;}
ll S(ll n,ll k)
{
	ll ans=0;
	for(int i=0;i<=k;i++)
	{
		if((k+i)%2)ans=((ans-C(k,i)*qmi(i,n)%mod)%mod+mod)%mod;
		else ans=((ans+C(k,i)*qmi(i,n)%mod)%mod+mod)%mod;
	}
	return ans*f[k]%mod;
}
int main()
{
	jie[0]=f[0]=inv[0]=1;
	for(ll i=1;i<200005;i++)
		inv[i]=qmi(i,mod-2);
	for(ll i=1;i<200005;i++)
		f[i]=f[i-1]*inv[i]%mod,jie[i]=jie[i-1]*i%mod;
	ll n,k,sum=0;
	scanf("%lld%lld",&n,&k);
	for(ll i=0;i<n;i++)
	{
		ll k;
		scanf("%lld",&k);
		sum=(sum+k)%mod;
	}
	printf("%lld\n",(S(n,k)+(n-1)*S(n-1,k)%mod)%mod*sum%mod);
}


猜你喜欢

转载自blog.csdn.net/acterminate/article/details/79832714