CF961G Partitions

Link

法一

每个数的贡献系数是一样的,我们枚举当前数所在集合的大小,那么答案为\((\sum\limits_{i=1}^nw_i)(\sum\limits_{i=1}^ni{n-1\choose i-1}\left\{n-i\atop k-1\right\})\)
可以利用多项式算法求出,比较复杂。

法二

我们设现在要求出\(x\)的贡献系数,划分好集合之后,当前情况的贡献就是\(x\)所在集合\(S\)的大小。
\(|S|\)可以分为\(x\)的贡献与其它数的贡献。
\(x\)的贡献:在任何一个划分方案中都有\(1\)的贡献,因此总贡献为\(\left\{n\atop k\right\}\)
其它数贡献:显然\(n-1\)个其它数的贡献都是一样的,因此我们现在考虑\(y\)的贡献。\(y\)\(1\)的贡献当且仅当\(x,y\)在同一个集合,方案数为\(\left\{n-1\atop k\right\}\)。因此总贡献为\((n-1)\left\{n-1\atop k\right\}\)
那么\(x\)的贡献系数就是\(\left\{n\atop k\right\}+(n-1)\left\{n-1\atop k\right\}\),答案就是\((\sum\limits_{i=1}^nw_i)(\left\{n\atop k\right\}+(n-1)\left\{n-1\atop k\right\})\)

#include<cstdio>
const int N=200007,P=1000000007;
int ifac[N];
int read(){int x;scanf("%d",&x);return x;}
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
void dec(int&a,int b){a-=b,a+=a>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int b){int r=1;for(;b;b>>=1,a=mul(a,a))if(b&1)r=mul(a,r);return r;}
int S(int n,int k){int r=0;for(int i=0;i<=k;++i) (i&1? dec:inc)(r,1ll*ifac[i]*pow(k-i,n)%P*ifac[k-i]%P);return r;}
int main()
{
    int n=read(),k=read(),sum=0;ifac[0]=1;
    for(int i=1;i<=n;++i) inc(sum,read());
    for(int i=1;i<=n;++i) ifac[i]=mul(ifac[i-1],pow(i,P-2));
    printf("%d",mul(sum,(S(n,k)+(n-1ll)*S(n-1,k))%P));
}
posted @ 2020-04-14 14:23  Shiina_Mashiro  阅读(155)  评论(0编辑  收藏  举报