题意

有一个长度为 \(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. Python2.7-csv

    csv模块,用于读写 csv 文件,常用 reader 和 writer 对象进行操作 1.模块的类 1.1 Dialect 对象,设置 csv 文件的各种格式,包括分隔符,引用符,转义符等 1.1. ...

  2. Vue复选框的全选

    <!DOCTYPE html><html>    <head>        <meta charset="utf-8">      ...

  3. flask 入门(二)

    Windows(提前安好virtualenv:pip  install  virtualenv) 一.准备: 1.启动pycharm 2.创建flask项目 二.基本库安装和设置 1.创建沙盒virt ...

  4. Intel 面试(就不该报外企,英语是硬伤)

    1 自我介绍(用英文) 啊啊啊,能不能用中文啊,最好用英文,蒙了.... 2 你对硬件了解吗,对X86系统了解吗,知道CPU是怎么处理读一个数据的吗,说说cpu从读一个数据,到内存怎么进行处理? 说的 ...

  5. 2.4《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——小结

    下Table 3本章重要命令小结 命令 描述 示例 > 将输出内容重定向到指定文件中 $ echo foo > foo.txt >> 将输出内容添加到指定问价中 $ echo ...

  6. 20155317王新玮《网络对抗》Exp2 后门原理与实践

    20155317王新玮<网络对抗>Exp2 后门原理与实践 一.实验内容 (1)使用netcat获取主机操作Shell,cron启动 (2)使用socat获取主机操作Shell, 任务计划 ...

  7. Scala学习(二)--- 控制结构和函数

    控制结构和函数 摘要: 本篇主要学习在Scala中使用条件表达式.循环和函数,你会看到Scala和其他编程语言之间一个根本性的差异.在Java或C++中,我们把表达式(比如3+4)和语句(比如if语句 ...

  8. 28 个 C/C++ 开源 JSON 程序库性能及标准符合程度评测

    28 个 C/C++ 开源 JSON 程序库性能及标准符合程度评测 坊间有非常多的 C/C++ JSON 库,怎么选择是一个难题. [nativejson-benchmark](https://git ...

  9. [CF983D]Arkady and Rectangles[线段树+可删堆/set]

    题意 你有一个无限大的绘图板,开始颜色是\(0\) , 你将进行\(n\) 次绘图,第\(i\) 次绘图会将左下角为 \((x_1, y_1)\),右上角为\((x_2, y_2)\) 的矩形涂成颜色 ...

  10. SpringBoot配置Aop笔记【例子】

    众所周知,spring最核心的两个功能是aop和ioc,即面向切面,控制反转.这里我们探讨一下如何使用spring aop. 1.何为aop aop全称Aspect Oriented Programm ...