泳池
题解
做这题时自闭了一个下午。还在自闭中。
看到这个图的第一眼时,笔者还未反应过来这题到底是什么。可能是笔者语文不好
先讲一下题意,我们只能在一个每个格子(其危险的概率为p),我们只能从底层开始画一个全是安全的矩阵面积为k时的概率。
我们发现,直接求这个概率不大方便,我们可以分别求出小于等于k的概率与小于等于k-1的概率,将它们相减即可。
可我们到底应该怎么做呢?考虑dp。
令为底面宽为i时的答案,为一个宽为i,高度为j的矩形,其中只有第j行有可能有危险。
状态转移方程式为:。
想后缀和一样,我们令,那么。
好像还是会超时,貌似还可以用多项式取模的方法来优化。
。
这样,就可以用卡过了,貌似还可以用FFT优化,不过笔者懒得打了。谁叫笔者是一个蒟蒻。
源码
巨佬没兴趣可以跳过。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#define MAXN 1005
using namespace std;
typedef long long LL;
#define int LL
const int mo=998244353;
#define gc() getchar()
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
int qkpow(int a,int s){
int t=1;
while(s){
if(s&1)t=t*a%mo;
a=a*a%mo;s>>=1;
}
return t;
}
int n,m,a,b,p,q;
int dp[MAXN][MAXN],g[MAXN][MAXN];
int powp[MAXN],g1[MAXN],f[MAXN<<1];
int res[MAXN<<2],tmp[MAXN<<2],x[MAXN<<2];
int solve(int k){
memset(dp,0,sizeof(dp));memset(g,0,sizeof(g));
memset(g1,0,sizeof(g1));memset(f,0,sizeof(f));
memset(res,0,sizeof(res));memset(x,0,sizeof(x));
for(int i=1;i<=k+2;i++)dp[0][i]=g[0][i]=1;
for(int i=1;i<=k;i++)
for(int j=k/i+1;j>1;j--){
for(int l=1;l<=i;l++)
dp[i][j]=(dp[i][j]+g[l-1][j+1]*g[i-l][j]%mo*powp[l-1]%mo*q%mo)%mo;
g[i][j]=(g[i][j+1]*powp[i]+dp[i][j])%mo;
}
for(int i=0;i<=k;i++)g1[i+1]=q*g[i][2]%mo*powp[i]%mo;f[0]=1;
for(int i=1;i<=k;i++){
f[i]=g[i][2]*powp[i]%mo;
for(int j=1;j<=i;j++)
f[i]=(f[i]+g1[j]*f[i-j]%mo)%mo;
}
k++;
for(int i=k;i<=k<<1;i++)
for(int j=1;j<=k;j++)
f[i]=(f[i]+g1[j]*f[i-j]%mo)%mo;
if(n<=k)return f[n];
int lim=1,L=0;
res[0]=1;x[1]=1;
for(int i=n-k;i>0;i>>=1){
if(i&1){
for(int i=0;i<=L+lim;i++)tmp[i]=0;
for(int i=0;i<=L;i++)
for(int j=0;j<=lim;j++)
tmp[i+j]=(tmp[i+j]+res[i]*x[j]%mo)%mo;
L+=lim;
for(int i=L;i>=k;i--)
for(int j=1;j<=k;j++)
tmp[i-j]=(tmp[i-j]+tmp[i]*g1[j])%mo;
L=min(L,k-1);
for(int i=0;i<=L;i++)res[i]=tmp[i];
}
for(int i=0;i<=2*lim;i++)tmp[i]=0;
for(int i=0;i<=lim;i++)
for(int j=0;j<=lim;j++)
tmp[i+j]=(tmp[i+j]+x[i]*x[j]%mo)%mo;
lim<<=1;
for(int i=lim;i>=k;i--)
for (int j=1;j<=k;j++)
tmp[i-j]=(tmp[i-j]+g1[j]*tmp[i]%mo)%mo;
lim=min(lim,k-1);
for(int i=0;i<=lim;i++)x[i]=tmp[i];
}
int ans=0;
for(int i=0;i<k;i++)ans=(ans+res[i]*f[i+k]%mo)%mo;
return ans;
}
signed main(){
read(n);read(m);read(a);read(b);
p=a*qkpow(b,mo-2)%mo;q=(mo+1-p)%mo;
powp[0]=1;for(int i=1;i<=m;i++)powp[i]=powp[i-1]*p%mo;
printf("%lld\n",(solve(m)-solve(m-1)+mo)%mo);
return 0;
}
谢谢!!!