2018.10.25【NOIP练习】01矩阵(组合数学)(数学期望)

传送门


解析:

请先确保你看懂了OJ上的提示的暴力做法再来看这个题解。

既然你已经会暴力了,那进入正题。
实际上我们就没有必要计算每个矩阵并求和,我们只需要枚举每个 i i i并计算 m i n { B i } = i min\{B_i\}=i min{Bi}=i的矩阵有多少个就行了。

现在考虑令矩阵一行的和为 i i i的方案数 f i f_i fi,显然 f i = C m i × x m − i × y i f_i=C_m^i\times x^{m-i}\times y^{i} fi=Cmi×xmi×yi

那么当一个矩阵 m i n { B j } = i min\{B_j\}=i min{Bj}=i的时候,必然每一行每一列的 B j B_j Bj ≥ i \geq i i,那么对于一行来说, B j ≥ i B_j\geq i Bji的概率就是 f j f_j fj的后缀和。

那么这道题可以 O ( m l o g n ) O(mlogn) O(mlogn)做完,因为计算概率是每行都要计算,需要一个快速幂。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

cs int mod=1000000007;

inline int quickpow(int a,int b,int res=1){
	for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)res=1ll*res*a%mod;
	return res;
}

cs int N=200005;
int n,m,x,y,suf,ans;
int fac[N],inv[N],ifac[N];

inline int C(cs int &n,cs int &m){
	return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}

signed main(){
	scanf("%d%d%d%d",&n,&m,&x,&y);
	fac[0]=fac[1]=inv[0]=inv[1]=ifac[0]=ifac[1]=1;
	for(int re i=2;i<=m;++i){
		fac[i]=1ll*fac[i-1]*i%mod;
		inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
		ifac[i]=1ll*ifac[i-1]*inv[i]%mod;
	}
	for(int re i=m;i;--i){
		suf=(suf+1ll*C(m,i)*quickpow(x,m-i)%mod*quickpow(y,i)%mod)%mod;
		ans=(1ll*ans+quickpow(suf,n))%mod;
	}
	cout<<ans<<endl;
	return 0;
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值