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

xiaoxiao2025-11-03  5

传送门


解析:

请先确保你看懂了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; }
转载请注明原文地址: https://www.6miu.com/read-5038994.html

最新回复(0)