Problem

一个n*m块砖的建筑,一共k天,每天风从两边吹,吹掉砖的概率为p,反之为1-p,求最终建筑没有倒塌的可能性(上层与下层有交集且每一层都有砖)

Solution

首先,我们可以预处理出pl[]和pr[]数组,表示k天后左右两边风吹到的位置的可能性

然后我们可以枚举层数,当前这一层的左右端点和上一层的左右端点,如果有公共部分则转移

这样的时间复杂度是O(n^5),显然我们可以用前缀和来优化:

引入f[i][r]+=dp[i][l][r](l <= r),再用一个sumr数组维护f数组的前缀和(suml数组是和sumr对称的)

那么dp[i][l][r]就等于总概率减去上一层区间在这个区间左边的概率和上一层区间在这个区间右边的概率(不相交的概率)

这样时间复杂度就降为了O(n2),我们再考虑优化使得时间复杂度降为O(n2):

我们再把dp降为两维,表示第i层最右边是j的概率

dp[i][j]=pl[l]pr[r](sumr[i-1][m] - suml[i-1][r+1] - sumr[i-1][l-1])

我们发现当l改变时,dp[i][j]改变的是可以再用前缀和维护的

于是时间复杂度变成了O(n^2)

Notice

前缀和预处理较多

Code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define sqz main
#define ll long long
#define reg register int
#define rep(i, a, b) for (reg i = a; i <= b; i++)
#define per(i, a, b) for (reg i = a; i >= b; i--)
#define travel(i, u) for (reg i = head[u]; i; i = edge[i].next)
const int INF = 1e9, mo = INF + 7, N = 1505, K = 100005;
const double eps = 1e-6, phi = acos(-1.0);
ll mod(ll a, ll b) {if (a >= b || a < 0) a %= b; if (a < 0) a += b; return a;}
ll read(){ ll x = 0; int zf = 1; char ch; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
void write(ll y) { if (y < 0) putchar('-'), y = -y; if (y > 9) write(y / 10); putchar(y % 10 + '0');}
ll p1[K], p2[K];
ll dp[N][N], suml[N][N], sumr[N][N], sum1[N], sum2[N], tt[K], pl[N], pr[N];
ll quickmo(ll x, int y)
{
ll ans = 1;
while (y)
{
if (y & 1) ans = ans * x % mo;
x = x * x % mo;
y /= 2;
}
return ans;
}
ll C(int n, int m)
{
return tt[m] * quickmo(tt[m - n], mo - 2) % mo * quickmo(tt[n], mo - 2) % mo;
}
int sqz()
{
int n = read(), m = read();
ll a = read(), b = read();
int k = read();
p1[0] = 1, p1[1] = a * quickmo(b, mo - 2) % mo;
p2[0] = 1, p2[1] = (b - a) * quickmo(b, mo - 2) % mo;
rep(i, 2, k) p1[i] = p1[i - 1] * p1[1] % mo, p2[i] = p2[i - 1] * p2[1] % mo;
tt[0] = 1;
rep(i, 1, k) tt[i] = tt[i - 1] * i % mo;
rep(i, 0, m - 1)
{
if (i > k) pl[i + 1] = 0;
else pl[i + 1] = C(i, k) * p1[i] % mo * p2[k - i] % mo;
pr[m - i] = pl[i + 1];
}
rep(i, 1, m) sum1[i] = (sum1[i - 1] + pl[i]) % mo;
sumr[0][m] = 1;
rep(i, 1, n)
{
rep(j, 1, m) sum2[j] = (sum2[j - 1] + pl[j] * sumr[i - 1][j - 1]) % mo;
rep(j, 1, m) dp[i][j] = (pr[j] * (sumr[i - 1][m] - suml[i - 1][j + 1]) % mo * sum1[j] % mo - pr[j] * sum2[j] % mo + mo) % mo;
rep(j, 1, m) suml[i][m - j + 1] = sumr[i][j] = (sumr[i][j - 1] + dp[i][j]) % mo;
}
printf("%lld\n", (sumr[n][m] + mo) % mo);
}

[Codeforces708E]Student's Camp的更多相关文章

  1. [CodeForces-708E]Student's Camp

    题目大意: 一个n*m的墙,被吹k天风,每块靠边的砖都有p的概率被吹掉. 如果上下两行没有直接相连的地方,我们则认为这一堵墙已经倒塌. 问最后墙不倒塌的概率(模意义). 思路: 动态规划. 用f[i] ...

  2. 【CF708E】Student's Camp 组合数+动态规划

    [CF708E]Student's Camp 题意:有一个n*m的网格,每一秒钟,所有左面没有格子的格子会有p的概率消失,右面没有格子的格子也会有p的概率消失,问你t秒钟后,整个网格的上边界和下边界仍 ...

  3. Student's Camp CodeForces - 708E (dp,前缀和优化)

    大意: $n$行$m$列砖, 白天左侧边界每块砖有$p$概率被摧毁, 晚上右侧边界有$p$概率被摧毁, 求最后上下边界连通的概率. 记${dp}_{i,l,r}$为遍历到第$t$行时, 第$t$行砖块 ...

  4. CF708E Student's Camp

    麻麻我会做*3100的计数了,我出息了 考虑朴素DP我们怎么做呢. 设\(f_{i,l,r}\)为第\(i\)层选择\(l,r\)的依旧不倒的概率. \(q(l,r)\)表示经历了\(k\)天后,存活 ...

  5. Codeforces 708E - Student's Camp(前缀和优化 dp)

    Codeforces 题目传送门 & 洛谷题目传送门 神仙 *3100,%%% 首先容易注意到 \(\forall i\in[1,m]\),第 \(i\) 行剩余的砖块一定构成一个区间,设其为 ...

  6. Codeforces Round #588 (Div. 2) D. Marcin and Training Camp(思维)

    链接: https://codeforces.com/contest/1230/problem/D 题意: Marcin is a coach in his university. There are ...

  7. java.io.NotSerializableException: test.io.file.Student

    java.io.NotSerializableException: test.io.file.Student    at java.io.ObjectOutputStream.writeObject0 ...

  8. 使用java反射机制编写Student类并保存

    定义Student类 package org; public class Student { private String _name = null; ; ; public Student() { } ...

  9. 参加MVP OpenDay 和2015 MVP Community Camp社区大课堂

    微软MVP Openday 1月30日在北京召开,到时全国上百位 MVP 专家将齐聚北京.当然还有亚太的其他国家地区的MVP 也会来北京,1月31日微软 MVP 项目组主办的年度微软技术社区分享大会- ...

随机推荐

  1. 使用pipeline减少与redis交互次数

    1.redis_pipeline=redis_cli.pipeline() 2.redis_pipeline.setex()此语句可写多条 3.redis_pipeline.execute() # # ...

  2. win10新系统修改onedrive目录,提示找不到OneDrive目录

    win10不知更新了什么,x1c非常卡一跳一跳的,很多年没见过了-_-!!( 原因排查:http://www.cnblogs.com/xuanmanstein/p/8878180.html). 于是重 ...

  3. linux下安装nginx以及常用命令指南

    安装nginx之前,要先在服务器上安装nginx运行所需要的依赖包 目录选择:一般选择 "/usr/local/" 1.安装PCRE库 离线安装包:https://pan.baid ...

  4. Linux简介和安装

    Andrew S. Tanenbaum参考Unix,写了Minix,并开源,Linus Torvalds以其为模板写了Linux. Linux包含内核版本和发行版本. Linux内核版本 Linux内 ...

  5. PHP const关键字

    常量是一个简单的标识符.在脚本执行期间该值不能改变(除了所谓的魔术常量,他们其实不是常量).常量默认大小写敏感.通常常量标识符总是大写的. 可以用define()函数来定义常量.在php5.3.0以后 ...

  6. json -- dump load dumps loads 简单对比

    json.dumps是将一个Python数据类型列表进行json格式的编码解析, 示例如下: >>> import json #导入python 中的json模块>>&g ...

  7. 第一阶段——站立会议总结DAY10

    1.昨天做了什么:找到了一些模板,把自己的修改了修改,排版了一下. 2.今天准备做什么:做最后的整理,添加一些小图标一些的.还要把按钮的字体换成红色. 3.遇到的困难:一般定义的文字和下拉菜单的文字的 ...

  8. grep 和curl -d等命令 单引号里面既使用正则,又使用变量的方法

    a='{"type":"d_log", "log_format":"d_log", "exclude" ...

  9. python-flask-配置文件的源码分析

    方式一:app.config['xx'] = 'xxx'源码分析:#第1步:class Flask(_PackageBoundObject):    self.config = self.make_c ...

  10. 1013. Pairs of Songs With Total Durations Divisible by 60总持续时间可被 60 整除的歌曲

    网址:https://leetcode.com/problems/pairs-of-songs-with-total-durations-divisible-by-60/submissions/ 参考 ...