题解 CF961G 【Partitions】

Kelin

2018-04-09 17:32:58

Solution

## [题意](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; } ```