【CF961G】Partitions
题意:给出n个物品,每个物品有一个权值$w_i$,定义一个集合$S$的权值为$W(S)=|S|\sum\limits_{x\in S} w_x$,定义一个划分的权值为$V(R)=\sum\limits_{S\in R} W(S)$。求将n个物品划分成k个集合的所有方案的权值和。
$n,k\le 2\cdot 10^5,w_i\le 10^9$
题解:第二类斯特林数针是太好用辣!
显然每个物品都是独立的,所以我们只需要处理出每个物品被统计的次数即可,说白了就是求这个式子:
$\sum\limits_{i=1}^niC_{n-1}^{i-1}S_{n-i}^{k-1}$
暴力拆分斯特林数
$\sum\limits_{i=1}^niC_{n-1}^{i-1}S_{n-i}^{k-1}\\=\sum\limits_{i=1}^niC_{n-1}^{i-1}\sum\limits_{j=0}^{k-1}{(-1)^j\over j!}{(k-j-1)^{n-i}\over (k-j-1)!}\\=\sum\limits_{j=0}^{k-1}{(-1)^j\over j!(k-j-1)!}\sum\limits_{i=1}^niC_{n-1}^{i-1}(k-j-1)^{n-i}$
考虑后面那个东西
$\sum\limits_{i=1}^niC_{n-1}^{i-1}(k-j-1)^{n-i}\\=\sum\limits_{i=1}^nC_{n-1}^{i-1}(k-j-1)^{n-i}+\sum\limits_{i=1}^n(i-1)C_{n-1}^{i-1}(k-j-1)^{n-i}\\=\sum\limits_{i=1}^nC_{n-1}^{i-1}(k-j-1)^{n-i}+(n-1)\sum\limits_{i=1}^nC_{n-2}^{i-2}(k-j-1)^{n-i}\\=(k-j)^{n-1}+(n-1)(k-j)^{n-2}$
就完事啦!
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const ll P=1000000007; typedef long long ll; const int maxn=300010; int n,k; ll sum,ans; ll jc[maxn],jcc[maxn],ine[maxn]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } inline ll pm(ll x,ll y) { if(y<0) return 1; ll z=1; while(y) { if(y&1) z=z*x%P; x=x*x%P,y>>=1; } return z; } int main() { n=rd(),k=rd(); int i,j; for(i=1;i<=n;i++) sum=(sum+rd())%P; ine[0]=ine[1]=jc[0]=jc[1]=jcc[0]=jcc[1]=1; for(i=2;i<=n;i++) ine[i]=P-(P/i)*ine[P%i]%P,jc[i]=jc[i-1]*i%P,jcc[i]=jcc[i-1]*ine[i]%P; for(j=0;j<=k-1;j++) { ll tmp=((j&1)?-1:1)*jcc[j]*jcc[k-1-j]%P; ans=(ans+tmp*pm(k-j,n-2)%P*(k-j+n-1))%P; } ans=(ans+P)%P; printf("%lld",ans*sum%P); return 0; }