博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

题解 [CF961G] Partitions

题面

解析

首先我们观察这个定义,

可以发现每个元素在统计答案时是平等的,

也就是单个元素的权值对答案没有特别的影响.

设元素权值为\(w[i]\),

那么我们就可以知道答案是\(\sum_{i=1}^nw[i]\)乘上一个系数.

而我们再次观察问题中的一个式子\(\left\vert s \right\vert*\sum\limits_iw[i]\),

实际上也就是把\(\sum\limits_iw[i]\)加了\(\left\vert s \right\vert\)次.

所以我们可以把它看成是集合中的每个元素都对答案造成了\(\sum\limits_iw[i]\)的贡献.

而贡献有两种情况:

  1. 元素自己给自己贡献

    这显然是总情况数\(S(n,k)\),\(S\)第二类斯特林数.

  2. 元素\(j\)\(i\)贡献(\(j!=i\))

    这里的情况数是\((n-1)*S(n-1,k)\).

    我们可以理解为先把除了\(i\)的元素分好,再把\(i\)加到其中一个里面.

    因为有还\(n-1\)个元素所以要乘\((n-1)\).

最后,答案就是\((S(n,k)+(n-1)*S(n-1,k))*\sum_{i=1}^nw[i]\).

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
#define int ll
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
using namespace std;

inline int read(){
	int sum=0,f=1;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
	return f*sum;
}

const int N=200001;
const int Mod=1000000007;
int n,m,sum,f,jc[N];

inline int fp(int a,int b){
	int ret=1;
	while(b){
		if(b&1) ret=(ll)ret*a%Mod;
		a=(ll)a*a%Mod;b>>=1;
	}
	return ret;
}

inline int inv(int x){
	return fp(x,Mod-2);
}

inline int stir(int n,int k){
	int ret=0;
	for(int j=0;j<k;j++) ret=(ret+fp(k-j,n)*inv(jc[j])%Mod*inv(jc[k-j])*((j&1)? -1:1))%Mod;
	return ret;
}

signed main(){
	n=read();m=read();jc[0]=1;
	for(int i=1;i<=n;i++) sum=(sum+read())%Mod;
	for(int i=1;i<=m;i++) jc[i]=jc[i-1]*i%Mod;
	int ans=sum*(stir(n,m)+stir(n-1,m)*(n-1)%Mod)%Mod;
	printf("%lld\n",(ans+Mod)%Mod);
	return 0;
}
posted @ 2019-07-13 20:34  Hastin  阅读(93)  评论(0编辑  收藏  举报