Codeforces 题目传送门 & 洛谷题目传送门

神仙 *3100,%%%

首先容易注意到 \(\forall i\in[1,m]\),第 \(i\) 行剩余的砖块一定构成一个区间,设其为 \([l_i,r_i]\)。

其次,由于第 \(0\) 行和第 \(m+1\) 行的砖块不可能被风吹走,因此该建筑物只可能被上下劈开,i.e.,该建筑物被劈开当且仅当 \(\exist i\in[1,m),[l_i,r_i]\cap[l_{i+1},r_{i+1}]=\varnothing\)。

这时候就可以考虑 \(dp\) 了,\(dp_{i,l,r}\) 表示考虑到第 \(i\) 行,第 \(i\) 行剩余的砖块组成的区间为 \([l,r]\) 的概率。因此我们就有了优秀的 \(n^5\) 的 \(dp\):\(dp_{i,l,r}=P(l,r)\times\sum\limits_{[l,r]\cap[l',r']\ne \varnothing}dp_{i-1,l',r'}\),其中 \(P(l,r)\) 为某一行被风吹得恰好只剩 \([l,r]\) 的概率,如果我们记 \(f(i)\) 表示恰好 \(i\) 个砖块被吹走的概率,那么有 \(f(i)=\dbinom{k}{i}p^i(1-p)^{k-i}\),\(P(l,r)=f(l-1)f(m-r)\)。

显然我们要对这个 \(dp\) 进行优化。怎么优化呢?考虑问题的反面,可拿概率减去 \([l,r]\cap[l',r']=\varnothing\) 的概率,显然概率为 \(\sum\limits_{1\le l\le r\le m}dp_{i-1,l,r}\),而 \([l,r]\cap[l',r']=\varnothing\) 当且仅当 \(r'<l\lor l'>r\),故 \([l,r]\cap[l',r']=\varnothing\) 的概率为 \(\sum\limits_{1\le l'\le r'<l}dp_{i-1,l,r}+\sum\limits_{r<l'\le r'\le m}dp_{i-1,l,r}\),因此 \(dp_{i,l,r}=P(l,r)(\sum\limits_{1\le l\le r\le m}dp_{i-1,l,r}-\sum\limits_{1\le l'\le r'<l}dp_{i-1,l,r}-\sum\limits_{r<l'\le r'\le m}dp_{i-1,l,r})\),如果我们记 \(R_{i,r}\) 为右端点为 \(r\) 的 \(dp_{i,l,r}\) 的和,\(L_{i,l}\) 为左端点为 \(l\) 的 \(dp_{i,l,r}\) 的和,那么我们可预处理 \(R_{i,r}\) 的前缀和与 \(L_{i,l}\) 的后缀和,这样可实现 \(\mathcal O(1)\) 转移,复杂度降到了 \(n^3\)。

但这样还是会炸,事实上,我们状态数已经达到了 \(\mathcal O(n^3)\),光是数组都远远开不下,因此考虑优化状态。我们考虑不计算 \(dp_{i,l,r}\),直接计算 \(R_{i,r},L_{i,l}\) 并写出它们的转移方程式。我们不妨进一步改写下 \(dp_{i,l,r}\) 的转移方程式,将 \(\sum\) 展开成关于 \(L_{i,l},R_{i,r}\) 的表达式,那么有 \(dp_{i,l,r}=f(l-1)f(m-r)(\sum\limits_{j=1}^mR_{i-1,j}-\sum\limits_{j=1}^{l-1}R_{i-1,j}-\sum\limits_{j=r+1}^mL_{i-1,j})\)。还需注意到的一点是,容易发现 \(L_{i,l}\) 的转移方程式与 \(R_{i,r}\) 高度相似,事实上如果我们把每一排翻转过来的话即可发现 \(R_{i,r}\) 变成了 \(L_{i,l}\),因此我们可以得到 \(L_{i,l}=R_{i,m-l+1}\),故上述方程可进一步改写为 \(dp_{i,l,r}=f(l-1)f(m-r)(\sum\limits_{j=1}^mR_{i-1,j}-\sum\limits_{j=1}^{l-1}R_{i-1,j}-\sum\limits_{j=1}^{m-r}R_{i-1,j})\),我们考虑直接将 \(R_{i,r},dp_{i,l,r}\) 的方程式合并,即不经过 \(dp_{i,l,r}\),直接根据 \(R_{i-1,j}\) 的值转移到 \(R_{i,j}\)

\[\begin{aligned}R_{i,r}&=\sum\limits_{l=1}^rdp_{i,l,r}\\&=\sum\limits_{l=1}^rf(l-1)f(m-r)(\sum\limits_{j=1}^mR_{i-1,j}-\sum\limits_{j=1}^{l-1}R_{i-1,j}-\sum\limits_{j=1}^{m-r}R_{i-1,j})\\&=f(m-r)((\sum\limits_{l=1}^rf(l-1)(\sum\limits_{j=1}^mR_{i-1,j}-\sum\limits_{j=1}^{m-r}R_{i-1,j}))-\sum\limits_{l=1}^r\sum\limits_{j=1}^{l-1}f(l-1)R_{i-1,j}\end{aligned}
\]

emmm……推到这一步应该就非常好维护了吧。

记 \(SR_{i,j}=\sum\limits_{r=1}^jR_{i,r}\),即 \(R_{i,j}\) 的前缀和,那么 \(R_{i,r}=f(m-r)((\sum\limits_{l=1}^rf(l-1)(SR_{i-1,m}-SR_{i-1,m-r}))-\sum\limits_{l=1}^rf(l-1)SR_{i-1,l-1}\)

显然 \(SR_{i-1,m}-SR_{i-1,m-r}\) 是常数,可 \(\mathcal O(1)\) 求出,因此我们只需处理 \(f(j)\) 的前缀和和 \(f(j)SR_{i-1,j}\) 的前缀和即可实现 \(\mathcal O(1)\) 转移。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1.5e3;
const int MAXK=1e5;
const int MOD=1e9+7;
int n,m,a,b,k,p,fac[MAXK+5],ifac[MAXK+5];
void init_fac(int n){
fac[0]=ifac[0]=ifac[1]=1;
for(int i=2;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i]*ifac[i-1]%MOD;
}
int d[MAXN+5],sd[MAXN+5],ss[MAXN+5];
int dp[MAXN+5][MAXN+5],sdp[MAXN+5][MAXN+5];
int binom(int x,int y){return 1ll*fac[x]*ifac[x-y]%MOD*ifac[y]%MOD;}
int qpow(int x,int e=MOD-2){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
int main(){
scanf("%d%d%d%d%d",&n,&m,&a,&b,&k);
p=1ll*a*qpow(b)%MOD;init_fac(k);
if(p==1){
if(k<=m) d[k]=1;
}
else{
int ivp=1ll*p*qpow(MOD+1-p)%MOD,pw=1;
for(int i=1;i<=k;i++) pw=1ll*pw*(MOD+1-p)%MOD;
for(int i=0;i<=m;i++) d[i]=1ll*binom(k,i)*pw%MOD,pw=1ll*pw*ivp%MOD;
}
sd[0]=d[0];for(int i=1;i<=m;i++) sd[i]=(sd[i-1]+d[i])%MOD;
dp[0][m]=1;sdp[0][m]=1;
for(int i=1;i<=n;i++){
memset(ss,0,sizeof(ss));
for(int j=1;j<=m;j++) ss[j]=(ss[j-1]+1ll*d[j]*sdp[i-1][j])%MOD;
for(int j=1;j<=m;j++){
dp[i][j]=1ll*d[m-j]*(1ll*(sdp[i-1][m]-sdp[i-1][m-j]+MOD)*sd[j-1]%MOD-ss[j-1]+MOD)%MOD;
// printf("%d %d %d\n",i,j,dp[i][j]);
}
for(int j=1;j<=m;j++) sdp[i][j]=(sdp[i][j-1]+dp[i][j])%MOD;
} printf("%d\n",sdp[n][m]);
return 0;
}

最新文章

  1. 【CodeForces 567E】President and Roads(最短路)
  2. struts2 CVE-2013-1965 S2-012 Showcase app vulnerability allows remote command execution
  3. jquery easyui-linkButton获取和设置按钮text并且解决火狐不支持innerText的方法
  4. Tcp抓包以及tcp状态解释
  5. 怎样合并排序数组(How to merge 2 sorted arrays?)
  6. 自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与空指令
  7. poj 1838
  8. [转载] Redis集群搭建最佳实践
  9. CCF-CSP 201709-4通信网络
  10. SSM-SpringMVC-25:SpringMVC异常顶级之自定义异常解析器
  11. 品阿里 Java 开发手册有感
  12. ISP PIPLINE(零) 知识综述预热
  13. maven web项目生成WebContent或WebRoot目录
  14. SQL SERVER 设置区别大小写
  15. JavaScript Drag处理
  16. windows下的gvim和emmet 下载和安装 + &quot;omnifunc is not set&quot; solution?
  17. jQuery源码解读二(apply和call)
  18. iOS分类Category探索
  19. 20145118 《Java程序设计》 第2周学习总结
  20. python实现八大排序算法

热门文章

  1. Bootstrap移动端导航(简易)
  2. leetcode 6/300 Z字型变换 py
  3. 单片机I/O口推挽与开漏输出详解(力荐)
  4. 常用Java API: ArrayList(Vector) 和 LinkedList
  5. Java并发:重入锁 ReentrantLock(二)
  6. AOP源码解析:AspectJExpressionPointcutAdvisor类
  7. ClickHouse实战
  8. UVA1104 Chips Challenge
  9. makefile简单学习(一)
  10. 难顶!面试官问我G1垃圾收集器