CF961G Partitions

题目描述:

luogu

题解:

斯特林数。

考虑每个$w_i$对答案的贡献。

当自己是一个集合时,每种情况下贡献为$1*w_i=w_i$,方案数为$S2(n,m)$;

当自己和别人在同一集合时,对于剩下的$n-1$个数有$S2(n-1,m)$种方案,而且自己可以放进任一集合中。

每一种贡献为$|S|*w_i$,合起来就是$(n-1)*w_i$。

求第二类斯特林数有容斥:$S2(n,m)= \frac{1}{m!} * \sum\limits_{k=0}^{m} (-1)^k C_m^k (m-k)^n$。利用至少有$k$个空盒时的方案数容斥。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 200050;
const int MOD = 1000000007;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
template<typename T>
inline void Mod(T&x){if(x>=MOD)x-=MOD;}
int n,m,S,jc[N],jny[N];
int fastpow(int x,int y)
{
    int ret = 1;
    while(y)
    {
        if(y&1)ret=1ll*ret*x%MOD;
        x=1ll*x*x%MOD;y>>=1;
    }
    return ret;
}
void init()
{
    jc[0] = 1;
    for(int i=1;i<=m;i++)jc[i]=1ll*jc[i-1]*i%MOD;
    jny[m]=fastpow(jc[m],MOD-2);
    for(int i=m;i;i--)jny[i-1]=1ll*jny[i]*i%MOD;
}
int C(int x,int y){return 1ll*jc[x]*jny[y]%MOD*jny[x-y]%MOD;}
int S2(int x,int y)
{
    int f = 0;
    for(int i=0;i<=y;i++)
        if(i&1)Mod(f+=MOD-1ll*C(y,i)*fastpow(y-i,x)%MOD);
        else Mod(f+=1ll*C(y,i)*fastpow(y-i,x)%MOD);
    return 1ll*f*jny[y]%MOD;
}
int main()
{
    read(n),read(m);init();
    for(int x,i=1;i<=n;i++)
        read(x),Mod(S+=x);
    printf("%lld\n",1ll*S*((S2(n,m)+1ll*(n-1)*S2(n-1,m)%MOD)%MOD)%MOD);
    return 0;
}
View Code

 

posted @ 2019-07-05 10:07  LiGuanlin  阅读(...)  评论(...编辑  收藏