题目链接
容易想到暴力:
f
[
i
]
[
l
]
[
r
]
f[i][l][r]
f[i][l][r]为前i行四连通,最后一行剩下的区间为
[
l
,
r
]
[l,r]
[l,r]的概率,前缀和优化转移可以做到
O
(
n
3
)
O(n^{3})
O(n3)。
发现瓶颈在于状态数,考虑利用左右独立的性质来优化。i这维无法避免,想要减少状态只能把单个改为前缀和,记
f
[
i
]
[
l
]
f[i][l]
f[i][l]为左端点为
l
l
l的所有DP值,
g
[
i
]
[
r
]
g[i][r]
g[i][r]为右端点为
r
r
r的所有DP值,
f
,
g
f,g
f,g的转移推出式子后可用前缀和优化到
O
(
1
)
O(1)
O(1),于是效率优化到
O
(
n
2
)
O(n^{2})
O(n2)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll P=1e9+7;
ll fpw(ll a,ll x){
ll s=1;
for(;x;x>>=1,(a*=a)%=P) if(x&1) (s*=a)%=P;
return s;
}
const int N=1505;
int n,m,k; ll x,y;
ll p[N],sp[N],f[N],g[N],cf[N],sf[N],cg[N],sg[N];
void sum(){
for(int i=1;i<=m;i++){
cf[i]=(cf[i-1]+f[i])%P,cg[i]=(cg[i-1]+g[i])%P;
sg[i]=(sg[i-1]+cg[i]*p[i])%P;
}
for(int i=m;~i;i--) sf[i]=(sf[i+1]+cf[i]*p[m-i])%P;
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
cin>>n>>m>>x>>y>>k;
(x*=fpw(y,P-2))%=P;
p[0]=1; for(int i=1;i<=k;i++) (p[0]*=(P+1-x))%=P; sp[0]=p[0];
for(int i=1;i<=m;i++){
p[i]=p[i-1]*x%P*fpw(P+1-x,P-2)%P*fpw(i,P-2)%P*(k-i+1)%P;
if(x==1 && i==k) p[i]=1;
sp[i]=(sp[i-1]+p[i])%P; //cout<<p[i]<<" ";
}
f[1]=g[m]=1; sum();
for(int i=1;i<=n;i++){ //cout<<"i="<<i<<endl;
for(int l=1;l<=m;l++){
f[l]=p[l-1]*(sf[l]-cg[l-1]*sp[m-l]%P+P)%P;
//cout<<f[l]<<" ";
} //puts("");
for(int r=1;r<=m;r++){
g[r]=p[m-r]*(sp[r-1]*cf[r]%P-sg[r-1]+P)%P;
//cout<<g[r]<<" ";
} //puts("");
sum();
}
cout<<cf[m]<<endl;
return 0;
}