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天只是 ...
随机推荐
- IT行业供应过剩?“减负路线”助你成为人人都想要的抢手开发
开发者的IT技能:良莠不齐,优秀的软件开发人员在招聘时往往可遇不可求.包括国家统计局在内的多家权威机构的报告提示,在数字化转型的浪潮下,市场对于软件开发人员的需求数量已经远远地超过现有开发者群体的数量 ...
- AtCoder Beginner Contest 224
AtCoder Beginner Contest 224 A - Tires 思路分析: 判断最后一个字符即可. 代码如下: #include <bits/stdc++.h> using ...
- echart3 力引导布局实现节点的提示和折叠
最近在项目中需要开发一个图表来显示人员的各种属性,类似于一种树形的结构进行显示数据.如果多个人员有同一个属性,那么需要将相同的属性进行连线,即关联起来.即形成一个关系图,由于我自身对echarts稍微 ...
- stm32看门狗详细解答,看了觉得一下子明白了很多
一.独立看门狗 STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效. 看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路 ...
- 21.10.14 test
题目 WOJ5078 到 WOJ5081 T1 Problem A \(\color{green}{100}\) 由于每轮要选择尽量多的边删除,所以想到无向图的生成树,因为在生成树上再加一条边就会形成 ...
- hdu 5090 Game with Pearls (额,, 想法题吧 / 二分图最大匹配也可做)
题意: 给你N个数,a1,,,,an.代表第i个管子里有ai个珍珠. 规定只能往每根管里增加k的倍数个珍珠. 如果存在一套操作,操作完毕后可以得到1~N的一个排列,则Jerry赢,否则Tom赢. 问谁 ...
- Delphi的手机程序隐藏顶部信号栏
把TForm的BorderStyle设置为None 记之!
- Mysql 5.7 集群部署,keepalived
参考文章: https://blog.csdn.net/f18770366447/article/details/80703347 https://www.cnblogs.com/benjamin77 ...
- Nginx高级特性实操
导读 nginx从入门到精通,点我直达 下载nginx与安装 点我直达 安装依赖 yum -y install gcc zlib zlib-devel pcre-devel openssl opens ...
- 端口扫描工具 nmap 使用手册
0x00 主机发现 -sL 仅仅是显示,扫描的IP数目,不会进行任何扫描 -sn ping扫描,即主机发现 -Pn 不检测主机存活 -PS/PA/PU/PY[portlist] TCP SYN Pin ...