题解 CF961G 【Partitions】
Kelin
2018-04-09 17:32:58
## [题意](https://blog.csdn.net/BeNoble_/article/details/79869837)
给出$n$ 个物品$,$ 每个物品有一个权值$w_i$
定义一个集合$S$ 的权值$W(S)=|S|\sum\limits_{x\in S}w_x$
定义一个划分的权值为$W'(R)=\sum\limits_{S\subseteq R}W(S)$
求将$n$ 个物品划分成$k$ 个集合的所有方案的权值和
$n,k\le2\times10^5,w_i\le10^9$
---
## 题解
考虑把每一个元素的贡献加起来
不难发现每个元素前的系数都是一样的$,$设系数是$p$
$$Ans=p\sum_{i=1}^n w_i$$
考虑枚举$i$所在的集合的大小$(S$表示第二了斯特林数$),$那么
$$p=\sum_{s=1}^ns{n-1\choose s-1}S_{n-s}^{k-1}$$
考虑到$S_n^m=\frac1{m!}\sum\limits_{i=0}^m(-1)^i{m\choose i}(m-i)^n$
$$=\sum_{s=1}^ns{n-1\choose s-1}\sum_{i=0}^{k-1}\frac{(-1)^i}{(k-1)!}{k-1\choose i}(k-i-1)^{n-s}$$
$$=\sum_{s=1}^ns{n-1\choose s-1}\sum_{i=0}^{k-1}\frac{(-1)^i}{i!}{(k-i-1)^{n-s}\over (k-i-1)!}$$
$$=\sum_{i=0}^{k-1}\frac{(-1)^i}{i!(k-i-1)!}\sum_{s=1}^ns{n-1\choose s-1}(k-i-1)^{n-s}$$
考虑$\sum_{s=1}^ns{n-1\choose s-1}(k-i-1)^{n-s}$
$$=\sum_{s=1}^n{n-1\choose s-1}(k-i-1)^{n-s}+\sum_{s=1}^n(s-1){n-1\choose s-1}(k-i-1)^{n-s}$$
考虑到$k{n\choose k}=n{n-1\choose k-1}$
$$=\sum_{s=1}^n{n-1\choose s-1}(k-i-1)^{n-s}+(n-1)\sum_{s=1}^n{n-2\choose s-2}(k-i-1)^{n-s}$$
考虑到$\sum\limits_{i=0}^n{n\choose i}(k-1)^{n-i}=k^n$
$$=(k-i)^{n-1}+(n-1)(k-i)^{n-2}$$
$$=(k-i)^{n-2}(k-i+n-1)$$
$$\Rightarrow p=\sum_{i=0}^{k-1}\frac{(-1)^i(k-i)^{n-2}}{i!(k-i-1)!}(k-i+n-1)$$
$O(k\log k)$递推即可
```
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
const int N=2e5+5,P=1e9+7;
typedef int arr[N];
typedef long long ll;
int n,k,Sum;arr fac,ifac;ll p;
inline int pls(int a,int b){return a+=b,a<P?a:a-P;}
inline int fpm(int a,int b){if(b<0)return 1;int x=1;for(;b;b>>=1,a=(ll)a*a%P)if(b&1)x=(ll)x*a%P;return x;}
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
sd(n),sd(k);int x;
fp(i,1,n)sd(x),Sum=pls(Sum,x);
fac[0]=1;fp(i,1,n)fac[i]=(ll)fac[i-1]*i%P;
ifac[n]=fpm(fac[n],P-2);fd(i,n,0)ifac[i-1]=(ll)ifac[i]*i%P;
fp(i,0,k-1)p+=(i&1?-1:1)*(ll)ifac[i]*ifac[k-i-1]%P*fpm(k-i,n-2)%P*(k-i+n-1)%P;
printf("%lld\n",(ll)pls(p%P,P)*Sum%P);
return 0;
}
```
然后你可以发现~~这玩意根本推不出来好吗,于是就~~有另外一种比较容易的方法
注意到$W(S)=|S|\sum\limits_{x\in S}w_x,$前面的系数是$|S|,$对于$i\in S$可以当做$|S|$中每个数都对$i$产生了一次贡献
那么我们只要枚举每一个数对$i$的贡献即可
$i$对自身的贡献显然是$S_n^k$
$j\neq i$时$,j$对$i$的贡献是$j$和$i$在同一个集合的方案数$,$也就是$S_{n-1}^k$
于是$p=S_n^k+(n-1)S_{n-1}^k$~~其实也可以从上面那些东西推出来的~~
用$S_n^m=\frac1{m!}\sum\limits_{i=0}^m(-1)^i{m\choose i}(m-i)^n=\sum\limits_{i=0}^m\frac{(-1)^i}{i!}\frac{(m-i)^n}{(m-i)!},O(k\log k)$算就好了
```
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
const int N=2e5+5,P=1e9+7;
typedef int arr[N];
typedef long long ll;
int n,k,Ans;arr fac,ifac;
inline int pls(int a,int b){return a+=b,a<P?a:a-P;}
inline int fpm(int a,int b){int x=1;for(;b;b>>=1,a=(ll)a*a%P)if(b&1)x=(ll)x*a%P;return x;}
inline int S(int n,int m){
ll tp=0;
fp(i,0,m)tp+=(i&1?-1:1)*(ll)fpm(m-i,n)*ifac[m-i]%P*ifac[i]%P;
return pls(tp%P,P);
}
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
sd(n),sd(k);int x;
fp(i,1,n)sd(x),Ans=pls(Ans,x);
fac[0]=1;fp(i,1,n)fac[i]=(ll)fac[i-1]*i%P;
ifac[n]=fpm(fac[n],P-2);fd(i,n,0)ifac[i-1]=(ll)ifac[i]*i%P;
Ans=(ll)Ans*pls(S(n,k),(ll)(n-1)*S(n-1,k)%P)%P;
printf("%d\n",Ans);
return 0;
}
```