CF961G Partitions

Link

法一

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

法二

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

#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));
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12697807.html