[Codeforces961G]Partitions

题意

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

定义一个集合 S 的权值 W ( S ) = | S | x S w x

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

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

n , k 2 × 10 5 , w i 10 9


题解

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

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

A n s = p i = 1 n w i

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

p = s = 1 n s ( n 1 s 1 ) S n s k 1

考虑到 S n m = 1 m ! i = 0 m ( 1 ) i ( m i ) ( m i ) n

= 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 = 1 n s ( n 1 s 1 ) i = 0 k 1 ( 1 ) i i ! ( k i 1 ) n s ( k i 1 ) !

= i = 0 k 1 ( 1 ) i i ! ( k i 1 ) ! s = 1 n s ( n 1 s 1 ) ( k i 1 ) n s

考虑 s = 1 n s ( n 1 s 1 ) ( k i 1 ) n s

= 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 ( n k ) = n ( n 1 k 1 )

= 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 = 0 n ( n 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 )

p = i = 0 k 1 ( 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 | x S w x , 前面的系数是 | S | , 对于 i S 可以当做 | S | 中每个数都对 i 产生了一次贡献

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

i 对自身的贡献显然是 S n k

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

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

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;
}

猜你喜欢

转载自blog.csdn.net/BeNoble_/article/details/79869837
今日推荐