Codeforces 708E - Student's Camp(前缀和优化 dp)
神仙 *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}\):
\]
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;
}
Codeforces 708E - Student's Camp(前缀和优化 dp)的更多相关文章
- LOJ 6089 小Y的背包计数问题 —— 前缀和优化DP
题目:https://loj.ac/problem/6089 对于 i <= √n ,设 f[i][j] 表示前 i 种,体积为 j 的方案数,那么 f[i][j] = ∑(1 <= k ...
- Codeforces 1132C - Painting the Fence - [前缀和优化]
题目链接:https://codeforces.com/contest/1132/problem/C 题意: 栅栏有 $n$ 个节,有 $q$ 个人可以雇佣来涂栅栏,第 $i$ 个人可以涂第 $l_i ...
- P5241 序列(滚动数组+前缀和优化dp)
P5241 序列 挺神仙的一题 看看除了dp好像没什么其他办法了 想着怎么构个具体的图出来,然鹅不太现实. 于是我们想办法用几个参数来表示dp数组 加了几条边肯定要的吧,于是加个参数$i$表示已加了$ ...
- CDOJ 1307 ABCDE 前缀和优化dp
ABCDE 题目连接: http://acm.uestc.edu.cn/#/problem/show/1307 Description Binary-coded decimal (BCD) is a ...
- bzoj 1044 [HAOI2008]木棍分割——前缀和优化dp
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044 前缀和优化. 但开成long long会T.(仔细一看不用开long long) #i ...
- bzoj 3398 [Usaco2009 Feb]Bullcow 牡牛和牝牛——前缀和优化dp / 排列组合
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3398 好简单呀.而且是自己想出来的. dp[ i ]表示最后一个牡牛在 i 的方案数. 当前 ...
- bzoj2431: [HAOI2009]逆序对数列(前缀和优化dp)
2431: [HAOI2009]逆序对数列 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 2312 Solved: 1330[Submit][Stat ...
- CF601C Kleofáš and the n-thlon(期望+前缀和优化dp)
传送门 解题思路 要求这个人的排名,我们可以先求出某个人比他排名靠前的概率,然后再乘上\(m-1\)即为答案.求某个人比他排名靠前可以用\(dp\),设\(f[i][j]\)表示前\(i\)场比赛某人 ...
- 5.19 省选模拟赛 小B的夏令营 概率 dp 前缀和优化dp
LINK:小B的夏令营 这道题是以前从没见过的优化dp的方法 不过也在情理之中. 注意读题 千万不要像我这个sb一样 考完连题意都不知道是啥. 一个长方形 要求从上到下联通的概率. 容易发现 K天只是 ...
随机推荐
- Sequence Model-week1编程题2-Character level language model【RNN生成恐龙名 LSTM生成莎士比亚风格文字】
Character level language model - Dinosaurus land 为了构建字符级语言模型来生成新的名称,你的模型将学习不同的名字,并随机生成新的名字. 任务清单: 如何 ...
- [对对子队]发布声明Beta
Beta版本的新功能 新增的游戏内容 循环部分关卡 Beta阶段我们制作了游戏的第4-6关,为循环部分关卡.这一部分的关卡设计以编程的循环思想为基础,在流水线中加入了新的命令--循环语句,并以此为核心 ...
- 热身 for computer industry
项目 内容 作业属于 班级博客 作业要求 作业要求 个人课程目标 掌握软件工程基础知识 具体有助方面 个人认知与规划 其他参考文献 博客Ⅰ 博客 Ⅱ 选择计算机 你为什么选择计算机专业?你认为你的条件 ...
- elasticsearch地理位置查询
elasticsearch地理位置查询 一.背景 二.geo数据类型 1.geo_point 2.geo_shape 三.此处对geo_point类型实战 1.背景 2.插入地点数据 1.创建索引 2 ...
- GT考试
比较神仙的$dp+KMP+Matrix$综合题目,比较值得一写 $0x00$:首先我打了一个爆搜 不过对正解并无任何启发...(逗比发言请忽略) $0x01$:基础$dp$ 状态还是比较好设的, 考虑 ...
- 上午小测3 T1 括号序列 && luogu P5658 [CSP/S 2019 D1T2] 括号树 题解
前 言: 一直很想写这道括号树..毕竟是在去年折磨了我4个小时的题.... 上午小测3 T1 括号序列 前言: 原来这题是个dp啊...这几天出了好几道dp,我都没看出来,我竟然折磨菜. 考试的时候先 ...
- Python SyntaxError: Missing parentheses in call to 'print'
下面的代码 print "hello world" 会出现下面的错误 SyntaxError: Missing parentheses in call to 'print' 因为写 ...
- hdu 4771 Stealing Harry Potter's Precious (BFS+状压)
题意: n*m的迷宫,有一些格能走("."),有一些格不能走("#").起始点为"@". 有K个物体.(K<=4),每个物体都是放在& ...
- Redis网络库源码分析(2)之启动服务器
一.从main开始 main函数定义在server.c中,它的内容如下: //server.c int main() { signal(SIGPIPE, SIG_IGN); //忽略SIGPIPE信号 ...
- Centos7+Postfix+Dovecot实现内网邮件收发
1. 前期准备: 主机:CentOS release 7.6.1810 (Core) #安装时选择邮件服务器 IP:192.168.71.108 #示例 本地yum源 #因为是内网,所以建 ...