CF708E题解
考虑 表示第 行左边被删了 个右边被删了 个的概率。
考虑用所有方案减去不连通的, 表示某行左边被删 个右边被删 个的的概率,有:
容易发现 的定义中左边和右边没有任何关系,所以可以写成 ,稍微写写有:
容易发现 的转移具有对称性,这样会导致 。( 也一样)
设 。
可以重写转移:
考虑对 进行转移而不是 。
容易发现 相当于 。
重新设 ,这样就只需要最后处理一个后缀和即可。
随便前缀和优化一下即可,复杂度 。
初始值 ,答案为 。
题外话,这题不值 *3100 吧。
#include<cstdio>
namespace SOLVE{
const int M=1505,mod=1e9+7;
int n,m,k,p,P[M],F[M],G[M],S1[M],S2[M];
inline int pow(int a,int b=mod-2){
int ans(1);for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;return ans;
}
inline void main(){
scanf("%d%d%d%d%d",&n,&m,S1,S2,&k);p=1ll*S1[0]*pow(S2[0])%mod;S1[0]=pow(mod+1-p,k);S2[0]=0;
const int&q=1ll*p*pow(mod+1-p)%mod;for(int i=1;i<m;++i)S1[i]=1ll*S1[i-1]*q%mod;
if(2*k<m)return printf("1"),void();if(p==1)return printf("0"),void();
P[0]=P[1]=1;for(int i=2;i<m&&i<=k;++i)P[i]=1ll*(mod-mod/i)*P[mod%i]%mod;
for(int i=1;i<m&&i<=k;++i)P[i]=1ll*(k-i+1)*P[i]%mod*P[i-1]%mod;
for(int i=0;i<m;++i)P[i]=1ll*P[i]*S1[i]%mod;S1[0]=P[0];F[0]=1;
for(int i=1;i<m;++i)S1[i]=(S1[i-1]+P[i])%mod;
for(int k=1;k<=n;++k){
const int&S(F[0]);for(int i=1;i<m;++i)S2[i]=(S2[i-1]+1ll*(mod-P[i])*F[m-i])%mod;
for(int i=0;i<m;++i)G[i]=(1ll*(S+mod-F[m-i])*S1[m-i-1]+S2[m-i-1])%mod*P[i]%mod;
for(int i=m-1;i>=0;--i)F[i]=(G[i]+F[i+1])%mod,G[i]=0;
}
printf("%d",F[0]);
}
}
signed main(){
SOLVE::main();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】