题意:给你长度为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); }