Loading

CF961G Partitions

CF961G Partitions

稍微想一下就可以列出下面的式子。

\[\sum_{i=1}^{n}w_i\sum_{j=1}^{n}j\binom{n-1}{j-1}\begin{Bmatrix}n-j\\k-1\end{Bmatrix} \]

可以打个暴力验证一下,发现式子对了,并且前面 \(\sum w_i\) 可以最后乘。

大概意思是统计每一个数对答案的贡献,枚举它所在集合的大小为 \(j\) ,然后补上 \(j-1\) 个数,最后乘上剩下 \(n-j\) 个数分成 \(k-1\) 个非空集合的方案数。

暴力程序应该尽量短一些,并且写的快一点。

const int N=1145;
#define mod 1000000007
inline int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*n*res%mod;return res;}
int n,k,w[N],S2[N][N],fac[N],ifc[N],ans;
int comb(int n,int m){return n<m?0:1ll*fac[n]*ifc[m]%mod*ifc[n-m]%mod;}
signed main(){
	n=read(),k=read();
	rep(i,1,n)w[i]=read();
	S2[0][0]=1;rep(i,1,n)rep(j,1,i)S2[i][j]=(S2[i-1][j-1]+1ll*S2[i-1][j]*j%mod)%mod;
	fac[0]=1;rep(i,1,n)fac[i]=1ll*i*fac[i-1]%mod;
	ifc[n]=qpow(fac[n],mod-2);per(i,n-1,0)ifc[i]=1ll*ifc[i+1]*(i+1)%mod;
	int tim=0,sum=0;
	for(int j=1;j<=n;++j)tim=(tim+1ll*j*comb(n-1,j-1)%mod*S2[n-j][k-1]%mod)%mod;
	for(int i=1;i<=n;++i)sum=(sum+w[i])%mod;
	ans=1ll*tim*sum%mod;
	cout<<ans<<'\n';
}

所以目前的目标是,求出

\[\sum_{i=1}^{n}i\binom{n-1}{i-1}\begin{Bmatrix}n-i\\k-1\end{Bmatrix}\\ \]

直接求一列斯特林数就能算了,只不过出题人不讲wood,mod=1e9+7 ,板子比较牛逼的人应该可以松过去。

不过这个式子看着感觉可以化简,想了想没啥思路,就暴力把斯特林数拆了。

斯特林数展开到组合数的式子:

\[\begin{Bmatrix}n\\m\end{Bmatrix}=\dfrac{1}{m!}\sum_{i=0}^{m}(-1)^{m-i}\binom{m}{i}i^n \]

带进去

\[=\sum_{i=1}^{n}i\binom{n-1}{i-1}\dfrac{1}{(k-1)!}\sum_{j=0}^{k-1}(-1)^{k-1-j}\binom{k-1}{j}j^{n-i}\\ \]

为了方便直接把 \(k\)\(1\) ,然后一波式子直接推到底。

\[\sum_{i=1}^{n}i\binom{n-1}{i-1}\dfrac{1}{k!}\sum_{j=0}^{k}(-1)^{k-j}\binom{k}{j}j^{n-i}\\ =\dfrac{1}{k!}\sum_{j=0}^{k}(-1)^{k-j}\binom{k}{j}\sum_{i=1}^{n}j^{n-i}i\binom{n-1}{i-1}\\ =\dfrac{1}{k!}\sum_{j=0}^{k}(-1)^{k-j}\binom{k}{j}(\sum_{i=1}^{n}j^{n-i}\binom{n-1}{i-1}+\sum_{i=1}^{n}j^{n-i}(i-1)\binom{n-1}{i-1})\\ =\dfrac{1}{k!}\sum_{j=0}^{k}(-1)^{k-j}\binom{k}{j}(\sum_{i=0}^{n-1}j^{n-1-i}\binom{n-1}{i}+\sum_{i=0}^{n-1}j^{n-1-i}i\binom{n-1}{i})\\ =\dfrac{1}{k!}\sum_{j=0}^{k}(-1)^{k-j}\binom{k}{j}((1+j)^{n-1}+(n-1)\sum_{i=0}^{n-1}j^{n-1-i}\dfrac{i}{n-1}\binom{n-1}{i})\\ =\dfrac{1}{k!}\sum_{j=0}^{k}(-1)^{k-j}\binom{k}{j}((1+j)^{n-1}+(n-1)\sum_{i=0}^{n-1}j^{n-1-i}\binom{n-2}{i-1})\\ =\dfrac{1}{k!}\sum_{j=0}^{k}(-1)^{k-j}\binom{k}{j}((1+j)^{n-1}+(n-1)\sum_{i=0}^{n-2}j^{n-2-i}\binom{n-2}{i})\\ =\dfrac{1}{k!}\sum_{j=0}^{k}(-1)^{k-j}\binom{k}{j}((1+j)^{n-1}+(n-1)(1+j)^{n-2})\\ \]

倒数第三步步用了个叫做吸收率的东西

\[\binom{n}{m}=\dfrac{n}{m}\binom{n-1}{m-1}\Leftrightarrow \dfrac{m}{n}\binom{n}{m}=\binom{n-1}{m-1} \]

现在可以 \(O(k\log k)\) 算了。 \(\log\) 应该是可以消掉的,不过意义不大。

于是我们得到了一个把多项式科技吊起来打的方法,码量,常数全部吊打,除了思维难度(

非常恶心的是,\(n=1\) 的时候,快速幂算 \((1+j)^{n-2}\) 会TLE。我劝这个出题人耗子尾汁,已经不讲wood地卡了多项式就别搞这种corner case

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define sz(v) (int)v.size()
typedef long long LL;
typedef double db;
template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
#define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return f?x:-x;
}
const int N=200005;
#define mod 1000000007
inline int qpow(int n,int k){if(k<0)return 0;int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*n*res%mod;return res;}
int n,k,sum,fac[N],ifc[N],ans;
int comb(int n,int m){return n<m?0:1ll*fac[n]*ifc[m]%mod*ifc[n-m]%mod;}
signed main(){
	n=read(),k=read()-1;
	rep(i,1,n)sum=(sum+read())%mod;
	fac[0]=1;rep(i,1,k)fac[i]=1ll*i*fac[i-1]%mod;
	ifc[k]=qpow(fac[k],mod-2);per(i,k-1,0)ifc[i]=1ll*ifc[i+1]*(i+1)%mod;
	for(int i=0;i<=k;++i){
		int tmp=1ll*comb(k,i)*(qpow(1+i,n-1)+1ll*(n-1)*qpow(1+i,n-2)%mod)%mod;
		(k-i)&1?ans=(ans+mod-tmp)%mod:ans=(ans+tmp)%mod;
	}
	ans=1ll*ans*ifc[k]%mod*sum%mod;
	cout<<ans<<'\n';
}
posted @ 2021-01-14 20:04  zzctommy  阅读(163)  评论(0编辑  收藏  举报