题意

有一个长度为 \(n\) 的数列 \(a\),有 \(m\) 个 操作,每个操作是给 \(a[l_i,r_i]\) 中的数都加一,一个操作有 \(p_i\) 的概率执行(否则不执行)。一个性质是任意两个区间不相交或完全包含(可重叠)。问执行完所有操作后 \(a\) 中最大值的期望。

\(n\le 10^5,m\le 5000,a\le 10^9\) 。

分析

想象一下多个不相交或完全包含的区间,他们的结构其实是一棵树。外层为父亲,内层为儿子。

要计算的是最大值的期望,而这个最大值是由多个操作得到的,所以无法分别计算期望再合并。解决这个问题的方法是先算出概率,再得到期望。

到最后,一个区间 \([l,r]\) 的最大值只可能是 \([mx,mx+q]\) 中的数(\(mx\) 为原序列中这个区间的最大值)。那么那么我们可以用这个东西来 dp。

设 \(f[x][j]\) 表示 \(x\) 点子树中的操作结束后,\(x\) 点表示的这个区间的最大值小于等于 \(mx_x+j\) 的概率。这样设计是因为若是等于的话,计算的时候转移还是要求前缀和,相当于是小于等于了。若 \(x\) 这个操作不执行,那么从子树 \(v\) 转移,子树 \(v\) 需要让其最后的区间最大值小于等于 \(mx_x+j\) ;若执行,那么子树的需要让其区间最大值小于等于 \(mx_i+j-1\) 。因此有转移

\[f[x][j]=p_x\prod f[v][mx_x+j-1-mx_v]+(1-p_x)\prod f[v][mx_x+j-mx_v]
\]

代码

#include<bits/stdc++.h>
using namespace std;
const int maxq=5e3+5;
const int maxm=1e4+5;
const int maxn=1e5+1;
int n,a[maxn],m,M,mx;
inline void Max(int &x,int y) {x=max(x,y);}
struct Q {
int l,r,mx;
double p;
inline bool operator < (const Q &b) const {return l!=b.l?l<b.l:r>b.r;}
} q[maxq];
namespace rmq {
const int maxj=17;
int f[maxn][maxj],bin[maxn];
void build() {
for (int i=2;i<=n;++i) bin[i]=bin[i>>1]+1;
for (int i=1;i<=n;++i) f[i][0]=a[i];
for (int j=1;j<maxj;++j) for (int i=1;i<=n;++i) {
int x=i+(1<<(j-1));
f[i][j]=f[i][j-1];
if (x<=n && f[x][j-1]>f[i][j]) f[i][j]=f[x][j-1];
}
}
inline int query(int l,int r) {
int x=bin[r-l+1];
return max(f[l][x],f[r-(1<<x)+1][x]);
}
}
namespace tree {
vector<int> g[maxq];
double f[maxq][maxm];
inline void add(int x,int y) {g[x].push_back(y);}
void build() {
sort(q+1,q+m+1);
static int sta[maxq],top;
q[sta[top=0]=0]=(Q){1,n,min(mx,m),0};
for (int i=1;i<=m;++i) {
Q &p=q[i];
for (;top>0 && p.l>q[sta[top]].r;--top) add(sta[top-1],sta[top]);
sta[++top]=i;
}
for (;top;--top) add(sta[top-1],sta[top]);
}
void dfs(int x) {
if (g[x].empty()) {
f[x][0]=1-q[x].p;
for (int i=1;i<=M;++i) f[x][i]=1;
return;
}
for (const int &v:g[x]) dfs(v);
for (int j=0;j<=m;++j) {
double fir=j?q[x].p:0,sec=1-q[x].p;
for (const int &v:g[x]) {
int the=q[x].mx-q[v].mx+j;
fir*=f[v][the-1];
sec*=f[v][the];
}
f[x][j]=fir+sec;
}
for (int j=m+1;j<=M;++j) f[x][j]=f[x][j-1];
}
double calc() {
double ret=mx;
for (int i=1;i<=m;++i) ret+=(f[0][i]-f[0][i-1])*i;
return ret;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
scanf("%d%d",&n,&m),M=m<<1;
for (int i=1;i<=n;++i) {
scanf("%d",a+i);
Max(mx,a[i]);
}
if (mx>m) for (int i=1;i<=n;++i) a[i]=max(0,a[i]+m-mx);
rmq::build();
for (int i=1;i<=m;++i) {
scanf("%d%d%lf",&q[i].l,&q[i].r,&q[i].p);
q[i].mx=rmq::query(q[i].l,q[i].r);
}
tree::build();
tree::dfs(0);
double ans=tree::calc();
printf("%.10lf\n",ans);
return 0;
}

Codeforces 494C - Helping People的更多相关文章

  1. [Codeforces-div.1 494C] Helping People

    [Codeforces-div.1 494C] Helping People 试题分析 不难注意到题目所给的性质是一棵树,所以肯定是树形dp. 那么期望没有办法合并,我们还有一种最笨的方法就是求出概率 ...

  2. CodeForces 1105E Helping Hiasat 最大独立集

    Helping Hiasat 题解: 如果我们把连续的2出现的人都相互连边的话, 题目就是问最大独立集的答案是多少. 求最大独立集可以将图变成反图, 然后求最大团. 代码: #include<b ...

  3. 【Codeforces 1105E】Helping Hiasat

    Codeforces 1105 E 题意:给你m个事件,每个事件可能是以下两种之一: \(1\),代表此时可以更改用户名 \(2\) \(s\),代表\(s\)来查看是否用户名与其名字相符 一共有\( ...

  4. Codeforces Round #533 (Div. 2) E - Helping Hiasat 最大团

    E - Helping Hiasat 裸的最大团,写了一种 2 ^ (m / 2)  * (m / 2)的复杂度的壮压, 应该还有更好的方法. #include<bits/stdc++.h> ...

  5. Codeforces #282 div 1 C Helping People 题解

    CF 282 C Helping People 题解 [原题] time limit per test 2 seconds memory limit per test 512 megabytes in ...

  6. Codeforces Round #533 (Div. 2) E. Helping Hiasat(最大独立集)

    题目链接:https://codeforces.com/contest/1105/problem/E 题意:有 n 个事件,op = 1 表示我可以修改昵称,op = 2 表示一个名为 s_i 的朋友 ...

  7. Solution -「CF 494C」Helping People

    \(\mathcal{Description}\)   Link.   给定序列 \(\{a_n\}\) 和 \(m\) 个操作,第 \(i\) 个操作有 \(p_i\) 的概率将 \([l_i,r_ ...

  8. Codeforces Round #802 (Div. 2)C. Helping the Nature(差分)

    题目链接 题目大意: 给你一个有n个元素的数组a,你可以通过一下三种操作使数组的每一个值都为0: 选择一个下标i,然后让a[1],a[2]....a[ i ] 都减一; 选择一个下标i,然后让a[i] ...

  9. Codeforces Round #439 (Div. 2) Problem E (Codeforces 869E) - 暴力 - 随机化 - 二维树状数组 - 差分

    Adieu l'ami. Koyomi is helping Oshino, an acquaintance of his, to take care of an open space around ...

随机推荐

  1. Android ListView下拉刷新时卡的问题解决小技巧

    问题:ListView下拉刷新时看上去非常的卡 解决方案: 在BaseAdapter的getView方法中,有三个参数 public View getView(int position, View c ...

  2. debian jessie 网络设置

    从stable更换到testing后,更新系统apt-get dist-upgrade,然后是等待, 然后不耐烦了不等了,关机! 第二天早上开机apt-get update,找不到源! 用ifconf ...

  3. 微信小程序开发 [01] 小程序基本结构和官方IDE简介

    1.小程序账户注册 实际上在进行开发时没有注册小程序账户也是可以的,官方提供的IDE提供实时编译模拟预览,和当前你有没有绑定小程序账户没有关系. 当然,最终你要正式上线你的小程序的话,肯定还是需要账户 ...

  4. 2017-2018 Exp8 Web基础 20155214

    目录 Exp8 Web基础 实验内容 建站过程 SQL注入 知识点 Exp8 Web基础 实验内容 实验环境 主机 Kali 靶机 Kali 实验工具 后台语言 'PHP' 服务器 'Apache' ...

  5. MySQL主从报错1594

    一.主从报错 Relay log read failure 问题原因,MySQL主从使用的是kvm虚拟机,物理机超分严重,在负载高的情况下会kill掉占用资源最多的虚拟机,再启动后导致主从失败 mys ...

  6. 原生 JS 实现手机验证码倒计时

    可以使用 pointer-events 来阻止元素成为鼠标事件的 target.html5 新增操作元素 class 类名的方式 classList. classList 方法 add(value): ...

  7. Jmeter(二十二)_jenkins配置gitlab插件与ant插件

    Docker部署接口自动化持续集成环境第四步,代码上传到远程仓库! 接上文:脚本上传Gitlab 服务器中的Jenkins通过Gitlab插件读取远程Git远程仓库中的代码,然后通过ant插件进行构建 ...

  8. EVA索赔系统JAVA拦截例外站点

    控制面板->JAVA->JAVA控制面板->安全->添加以下例外站点: https://aftersales.i.daimler.com https://swdist.afte ...

  9. GitLab篇之Linux下环境搭建

    之前公司一直在使用微软的VSS和SVN做为源代码管理工具,考虑到VSS和SVN的局限性,个人一直建议我们应该采用Git来管理我们的源代码.Git的好处不多说相信大家也都知道的.Git不仅仅是一个源代码 ...

  10. Leetcode(力扣) 整数反转

    Leetcode 7.整数反转 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例: 输入: -123 输出: -321 注意: 假设我们的环境只能存储得下 32 位的有符 ...