请先确保你看懂了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×xm−i×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 Bj≥i的概率就是 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; }