CF961G Partitions
题目描述:
题解:
斯特林数。
考虑每个$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; }