[Codeforces961G]Partitions

xiaoxiao2021-02-28  34

题意

给出 n n 个物品,, 每个物品有一个权值 wi w i

定义一个集合 S S 的权值W(S)=|S|xSwxW(S)=|S|∑x∈Swx

定义一个划分的权值为 W(R)=SRW(S) W ′ ( R ) = ∑ S ⊆ R W ( S )

求将 n n 个物品划分成kk 个集合的所有方案的权值和

n,k2×105,wi109 n , k ≤ 2 × 10 5 , w i ≤ 10 9


题解

考虑把每一个元素的贡献加起来

不难发现每个元素前的系数都是一样的 , , 设系数是pp

Ans=pi=1nwi A n s = p ∑ i = 1 n w i

考虑枚举 i i 所在的集合的大小(S(S表示第二了斯特林数 ), ) , 那么

p=s=1ns(n1s1)Sk1ns p = ∑ s = 1 n s ( n − 1 s − 1 ) S n − s k − 1

考虑到 Smn=1m!i=0m(1)i(mi)(mi)n S n m = 1 m ! ∑ i = 0 m ( − 1 ) i ( m i ) ( m − i ) n

=s=1ns(n1s1)i=0k1(1)i(k1)!(k1i)(ki1)ns = ∑ s = 1 n s ( n − 1 s − 1 ) ∑ i = 0 k − 1 ( − 1 ) i ( k − 1 ) ! ( k − 1 i ) ( k − i − 1 ) n − s

=s=1ns(n1s1)i=0k1(1)ii!(ki1)ns(ki1)! = ∑ s = 1 n s ( n − 1 s − 1 ) ∑ i = 0 k − 1 ( − 1 ) i i ! ( k − i − 1 ) n − s ( k − i − 1 ) !

=i=0k1(1)ii!(ki1)!s=1ns(n1s1)(ki1)ns = ∑ i = 0 k − 1 ( − 1 ) i i ! ( k − i − 1 ) ! ∑ s = 1 n s ( n − 1 s − 1 ) ( k − i − 1 ) n − s

考虑 ns=1s(n1s1)(ki1)ns ∑ s = 1 n s ( n − 1 s − 1 ) ( k − i − 1 ) n − s

=s=1n(n1s1)(ki1)ns+s=1n(s1)(n1s1)(ki1)ns = ∑ s = 1 n ( n − 1 s − 1 ) ( k − i − 1 ) n − s + ∑ s = 1 n ( s − 1 ) ( n − 1 s − 1 ) ( k − i − 1 ) n − s

考虑到 k(nk)=n(n1k1) k ( n k ) = n ( n − 1 k − 1 )

=s=1n(n1s1)(ki1)ns+(n1)s=1n(n2s2)(ki1)ns = ∑ s = 1 n ( n − 1 s − 1 ) ( k − i − 1 ) n − s + ( n − 1 ) ∑ s = 1 n ( n − 2 s − 2 ) ( k − i − 1 ) n − s

考虑到 i=0n(ni)(k1)ni=kn ∑ i = 0 n ( n i ) ( k − 1 ) n − i = k n

=(ki)n1+(n1)(ki)n2 = ( k − i ) n − 1 + ( n − 1 ) ( k − i ) n − 2

=(ki)n2(ki+n1) = ( k − i ) n − 2 ( k − i + n − 1 )

p=i=0k1(1)i(ki)n2i!(ki1)!(ki+n1) ⇒ p = ∑ i = 0 k − 1 ( − 1 ) i ( k − i ) n − 2 i ! ( k − i − 1 ) ! ( k − i + n − 1 )

O(klogk) 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|xSwx, W ( S ) = | S | ∑ x ∈ S w x , 前面的系数是 |S|, | S | , 对于 iS i ∈ S 可以当做 |S| | S | 中每个数都对 i i 产生了一次贡献

那么我们只要枚举每一个数对ii的贡献即可

i i 对自身的贡献显然是SknSnk

ji j ≠ i ,j , j i i 的贡献是jj i i 在同一个集合的方案数,,也就是 Skn1 S n − 1 k

于是 p=Skn+(n1)Skn1 p = S n k + ( n − 1 ) S n − 1 k 其实也可以从上面那些东西推出来的

Smn=1m!i=0m(1)i(mi)(mi)n=i=0m(1)ii!(mi)n(mi)!,O(klogk) S n m = 1 m ! ∑ i = 0 m ( − 1 ) i ( m i ) ( m − i ) n = ∑ i = 0 m ( − 1 ) i i ! ( 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; }
转载请注明原文地址: https://www.6miu.com/read-2631262.html

最新回复(0)