题目大意
在一个
n×m
的矩阵里面所有位置随机填入
0
或
(其实就是把每个位置
x+y
种情况暴力填然后对
min{Bi}
求和)。
n,m,x,y≤2×105
题目分析
naive的70分做法
令
fi
表示
m
个数(一行)和为
fi=(mi)xm−iyi
令 gi 表示 m 个数(一行)和大于等于
考虑枚举最大值是多少,多少个 B 是等于这个最大值,那么答案显然为
这样做是 O(n2) 的。
100分做法
上面的方法太弱逊水了。
考虑容斥原理。
最小值为
w
的方案数为
于是就可以愉快地统计答案了:
∑i=0m(gni−gni+1)i
这样做是 O(n) 的。
代码实现
#include <iostream>
#include <cstdio>
using namespace std;
const int P=1000000007;
const int N=200500;
int fact[N],invf[N],F[N],G[N],xp[N],yp[N],Gp[N];
int n,m,X,Y,ans;
int quick_power(int x,int y)
{
int ret=1;
for (;y;y>>=1,x=1ll*x*x%P) if (y&1) ret=1ll*ret*x%P;
return ret;
}
void pre()
{
int l=max(n,m);
fact[0]=1;
for (int i=1;i<=l;i++) fact[i]=1ll*fact[i-1]*i%P;
invf[l]=quick_power(fact[l],P-2);
for (int i=l;i>=1;i--) invf[i-1]=1ll*invf[i]*i%P;
xp[0]=yp[0]=1;
for (int i=1;i<=m;i++) xp[i]=1ll*xp[i-1]*X%P,yp[i]=1ll*yp[i-1]*Y%P;
}
inline int C(int n,int m){return 1ll*fact[n]*invf[m]%P*invf[n-m]%P;}
void calc()
{
for (int i=0;i<=m;i++) F[i]=1ll*C(m,i)*xp[m-i]%P*yp[i]%P;
G[m+1]=0;
for (int i=m;i>=0;i--) G[i]=(G[i+1]+F[i])%P;
ans=0;
for (int i=0;i<=m;i++) Gp[i]=quick_power(G[i],n);
for (int i=1;i<=m;i++) (ans+=1ll*(((Gp[i]-Gp[i+1])%P+P)%P)*i%P)%=P;
}
int main()
{
freopen("past.in","r",stdin),freopen("past.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&X,&Y);
pre(),calc();
printf("%d\n",ans);
fclose(stdin),fclose(stdout);
}