CF961G Partitions

传送门

luogu

显然每个数的贡献可以一起算感性理解一下,于是答案就是权值总和乘以每个数被算了几次

那个"集合大小为\(|S|\)的集合权值为权值和乘\(|S|\)",可以看成一个数所在集合每有一个数,这个数就要算一次,于是那个次数就是所有情况中有某个数和多少次数出现在过同一个集合中.首先他一直会和自己在同一个集合,所以方案为\(S(n,k)\).然后对于其他数,方案为\(S(n-1,k)*(n-1)\),也就是其他数先放好,然后其他所有数都会让当前这个数多加1次

关于\(S(n,k)\)强烈安利这里

#include<bits/stdc++.h>
#define LL long long
#define db double
#define il inline
#define pb push_back
#define mk make_pair
#define ft first
#define sc second

using namespace std;
const int N=200000+10,mod=1e9+7;
il LL rd()
{
    LL x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int n,k,sm,fac[N],iac[N],inv[N];
LL fpow(int a,int b){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;} return an;}
LL C(int n,int m){return m<0||n<m?0:1ll*fac[n]*iac[m]%mod*iac[n-m]%mod;}
LL S(int n,int m)
{
    LL an=0;
    for(int i=0;i<=m;++i)
    {
        int x=1ll*C(m,i)*fpow(m-i,n)%mod;
        an=(an+((i&1)?mod-x:x))%mod;
    }
    return 1ll*an*iac[m]%mod;
}

int main()
{
    n=rd(),k=rd();
    for(int i=1;i<=n;++i) sm=(sm+rd())%mod;
    fac[0]=1;
    for(int i=1;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod;
    iac[n]=fpow(fac[n],mod-2);
    for(int i=n;i;--i) iac[i-1]=1ll*iac[i]*i%mod;
    cout<<1ll*(S(n,k)+1ll*S(n-1,k)*(n-1)%mod)%mod*sm%mod;
    return 0;
}
posted @ 2019-03-10 22:28  ✡smy✡  阅读(165)  评论(0编辑  收藏  举报