题意:
给出一个数列wi,对于一个集合S,,对于一个w的划分R,
,求w的所有划分为k部分的W之和。
题解:
有一个显然的事实是:每个数字是等价的,也就是说每个数字wi单独来看,他在最终答案中的贡献都是p*wi,p是计算出来的一个系数。因此 答案=p*Σwi。
单独考虑每一个wx,设S是一个包含wx的集合,,那么wx对这个集合的贡献是|S|*wx,这个|S|可以分均到S中每一个元素身上,即和wx在同一个集合中每一个元素(包括wx自己)给wx带来了1的贡献。因此我们转而考虑每个数字给wx带来的贡献是多少,首先wx自己给自己带来的贡献是S(n,k),即每种划分中自己给自己的贡献都是1。其次对于剩下的每一个wy给wx的贡献是相等的S(n-1,k),即不考虑wx,剩下n-1个数字分成k部分,然后找到wy,把wx加入进去
所以系数p=S(n,k)+(n-1)*S(n-1,k),所以答案=(Σwi)*p
由于n,k比较大,因此不能使用递推方式计算S,需要用到第二类斯特林数S的展开式

这个展开式是一个容斥的计算式,首先S的意义是将n个数字分到m个不可区分盒子且m个盒子都不是空的的方案数。1/m!的意思是先把盒子看成是可区分的,然后除以m!就是S了;(-1)^k是容斥系数;C(m,k)*(m-k)^n的意思是m个盒子中有k个是空的的方案数。其实知道了容斥的计算原理,这个公式是很容易直接现场推算出来的。
根绝这个公式,我们只需要预处理阶乘值,根绝阶乘值计算组合数C,快速幂等等基本姿势。
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9+7;
const int maxn = 2e5+100;
int fac[maxn];
int n,k;
int power(int x,int y){
int ans=1;
while (y){
if (y&1){
ans = 1LL*ans*x%MOD;
}
x = 1LL*x*x%MOD;
y>>=1;
}
return ans;
}
int C(int x,int y){
return 1LL*fac[x]*power(fac[y],MOD-2)%MOD*power(fac[x-y],MOD-2)%MOD;
}
int S(int x,int y){
LL res = 0;
for (int i=0,flag=1;i<=y;i++,flag=-flag){
res+=1LL*flag*C(y,i)*power(y-i,x)%MOD;
res=(res+MOD)%MOD;
}
return res*power(fac[y],MOD-2)%MOD;
}
void init(){
fac[0]=1;
for (int i=1;i<maxn;i++){
fac[i] = 1LL*fac[i-1]*i%MOD;
}
}
int main(){
init();
cin>>n>>k;
int sum =0;
for (int i=0;i<n;i++){
int ai;
scanf("%d",&ai);
sum+=ai;
if (sum>=MOD){
sum-=MOD;
}
}
cout<<1LL*sum*((S(n,k)+1LL*(n-1)*S(n-1,k)%MOD)%MOD)%MOD<<endl;
return 0;
}