[PKUWC2018]Minimax 题解
根据题意,若一个点有子节点,则给出权值;否则可以从子节点转移得来。
若没有子节点,则直接给出权值;
若只有一个子节点,则概率情况与该子节点完全相同;
若有两个子节点,则需要从两个子节点中进行转移。
如何转移?显然,若权值 $i$ 在左子树,要取到它,需要在 $p_i$ 的概率中左子树较大,在 $(1-p_i)$ 的概率中左子树较小,右子树同理。因为当权值 $i$ 在左子树时右子树取到它的概率为 $0$ ,因此可以直接将两个子树的转移式相加合并,没有影响。即:
设节点 $x$ 取到权值 $i$ 的概率为 $f_{x,i}$ ,节点数为 $n$ ,则有:
$$f_{x,i}=f_{lson(x),i}*(p_x*\sum_{j=1}^{i-1} f_{rson(x),j}+(1-p_x)*\sum_{j=i+1}^{n} f_{rson(x),j})+f_{rson(x),i}*(p_x*\sum_{j=1}^{i-1} f_{lson(x),j}+(1-p_x)*\sum_{j=i+1}^{n} f_{lson(x),j})$$
如何求值?通过观察可以发现,这个式子同时需要左儿子的值、右儿子的值以及其前缀、后缀和,可以想到用线段树合并进行求值。
如何实现?在线段树合并的同时维护前、后缀和,打上乘法标记即可。记得离散化。
本题需要用到分数取模:$\frac{a}{b}\bmod k=\frac{a}{b}*b^{k-1}\bmod k=a*b^{k-2}\bmod k$ 。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=3e5+100;
const int P=998244353;
int qpow(int x,int y)
{
int ans=1;
while(y)
{
if(y&1)
ans=1LL*ans*x%P;
x=1LL*x*x%P,y>>=1;
}
return ans;
}//快速幂
const int D=qpow(10000,P-2);
struct Seg
{
int lson,rson,sum,tag;
#define lson(i) t[i].lson
#define rson(i) t[i].rson
#define sum(i) t[i].sum
#define tag(i) t[i].tag//乘法标记
}t[N<<5];
int n,cnt,h,ans;
int v[N],r[N],a[N],cnts[N],anss[N],s[N][2];
int newp()
{
int p=++cnt;
tag(p)=1;
return p;
}//新建节点
void update(int p,int val)
{
sum(p)=1LL*sum(p)*val%P;
tag(p)=1LL*tag(p)*val%P;
}//更新
void pushdown(int p)
{
if(tag(p)>1)
update(lson(p),tag(p)),update(rson(p),tag(p)),tag(p)=1;
}//下传标记
void change(int &p,int l,int r,int k,int val)
{
if(!p)
p=newp();
if(l==r)
{
sum(p)=val;
return ;
}
pushdown(p);
int mid=l+r>>1;
if(k<=mid)
change(lson(p),l,mid,k,val);
else
change(rson(p),mid+1,r,k,val);
sum(p)=sum(lson(p))+sum(rson(p))%P;
}//修改
void ask(int p,int l,int r)
{
if(!p)
return ;
if(l==r)
{
anss[l]=sum(p);
return ;
}
pushdown(p);
int mid=l+r>>1;
ask(lson(p),l,mid),ask(rson(p),mid+1,r);
}//输出答案到对应数组
int merge(int x,int y,int l,int r,int xtag,int ytag,int val)
{
if(!x && !y)
return 0;
if(!x)
{
update(y,ytag);
return y;
}
if(!y)
{
update(x,xtag);
return x;
}
pushdown(x),pushdown(y);//下传标记
int mid=l+r>>1,lx=sum(lson(x)),ly=sum(lson(y)),rx=sum(rson(x)),ry=sum(rson(y));//先存值,否则之后会被改动
lson(x)=merge(lson(x),lson(y),l,mid,(xtag+1LL*ry*(1-val+P)%P)%P,(ytag+1LL*rx*(1-val+P)%P)%P,val);
rson(x)=merge(rson(x),rson(y),mid+1,r,(xtag+1LL*ly*val%P)%P,(ytag+1LL*lx*val%P)%P,val);
sum(x)=(sum(lson(x))+sum(rson(x)))%P;
return x;
}
void pre()
{
sort(a+1,a+h+1);
for(int i=1;i<=n;i++)
if(!cnts[i])
v[i]=lower_bound(a+1,a+h+1,v[i])-a;//权值离散化
else
v[i]=1LL*v[i]*D%P;//存概率,分数取模
}//预处理权值
void solve(int x)
{
if(!cnts[x])
{
change(r[x],1,h,v[x],1);
return ;
}//没有子节点,插入权值
if(cnts[x]==1)
{
solve(s[x][0]);
r[x]=r[s[x][0]];
return ;
}//只有一个子节点
solve(s[x][0]),solve(s[x][1]);
r[x]=merge(r[s[x][0]],r[s[x][1]],1,h,0,0,v[x]);//有两个子节点
}
int main()
{
scanf("%d",&n);
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
if(x)
s[x][cnts[x]++]=i;
}
for(int i=1,x;i<=n;i++)
{
scanf("%d",&v[i]);
if(!cnts[i])
a[++h]=v[i];
}
pre(),solve(1),ask(r[1],1,h);
for(int i=1;i<=h;i++)
ans=(ans+1LL*i*a[i]%P*anss[i]%P*anss[i])%P;//计算答案
printf("%d",ans);
return 0;
}
[PKUWC2018]Minimax 题解的更多相关文章
- LOJ2537:[PKUWC2018]Minimax——题解
https://loj.ac/problem/2537 参考了本题在网上能找到的为数不多的题解. 以及我眼睛瞎没看到需要离散化,还有不开longlong见祖宗. ——————————————————— ...
- 【题解】PKUWC2018简要题解
[题解]PKUWC2018简要题解 Minimax 定义结点x的权值为: 1.若x没有子结点,那么它的权值会在输入里给出,保证这类点中每个结点的权值互不相同. 2.若x有子结点,那么它的权值有p的概率 ...
- BZOJ5461: [PKUWC2018]Minimax
BZOJ5461: [PKUWC2018]Minimax https://lydsy.com/JudgeOnline/problem.php?id=5461 分析: 写出\(dp\)式子:$ f[x] ...
- 题解-PKUWC2018 Minimax
Problem loj2537 Solution pkuwc2018最水的一题,要死要活调了一个多小时(1h59min) 我写这题不是因为它有多好,而是为了保持pkuwc2018的队形,与这题类似的有 ...
- [PKUWC2018] Minimax
Description 给定一棵 \(n\) 个节点的树,每个节点最多有两个子节点. 如果 \(x\) 是叶子,则给定 \(x\) 的权值:否则,它的权值有 \(p_x\) 的概率是它子节点中权值的较 ...
- BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)
BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...
- LOJ2537 PKUWC2018 Minimax 树形DP、线段树合并
传送门 题意:自己去看 首先可以知道,每一个点都有几率被选到,所以$i$与$V_i$的关系是确定了的. 所以我们只需要考虑每一个值的取到的概率. 很容易设计出一个$DP$:设$f_{i,j}$为在第$ ...
- [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)
还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...
- 【洛谷5298】[PKUWC2018] Minimax(树形DP+线段树合并)
点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...
随机推荐
- 服务治理框架dubbo中zookeeper的使用
Zookeeper提供了一套很好的分布式集群管理的机制,就是它这猴子那个几月层次型的目录树的数据结构,并对书中的节点进行有效的管理,从而可以设计出多种多样的分布式的数据管理模型:下面简要介绍下zook ...
- api接口返回动态的json格式?我太难了,尝试一下 linq to json
一:背景 1. 讲故事 前段时间和一家公司联调api接口的时候,发现一个奇葩的问题,它的api返回的json会动态改变,简化如下: {"Code":101,"Items& ...
- nvidia-smi:控制您的GPU
翻译 https://www.microway.com/hpc-tech-tips/nvidia-smi_control-your-gpus/ 大多数用户知道如何检查其CPU的状态,查看多少系统内存 ...
- Linux学习笔记之ubuntu安装与配置
1.打开虚拟机,点击新建虚拟机 2.安装向导 选择自定义安装 点击包含一个空白的硬盘 选择linux操作系统,版本是ubuntu 设置虚拟机的名称,可以自己写,还有保存的位置也可自选 根据自己电脑性能 ...
- 基于Python的AT命令测试脚本
对于各种有线&无线调制解调器(modem)产品来说,AT命令是事实上的标准接口之一,在工业界被广泛使用. 我开发了一套基于Python的AT命令测试脚本,源代码可在github上获取: htt ...
- 新司机的致胜法宝,使用ApexSql Log2018快速恢复数据库被删除的数据
作为开发人员,误操作数据delete.update.insert是最正常不过的了,比如: 删除忘记加where条件: 查询为了图方便按了F5,但是数据里面夹杂着delete语句. 不管是打着后发动机声 ...
- SPP、ASPP、RFB、CBAM
SPP:ASPP:将pooling 改为了 空洞卷积RFB:不同大小的卷积核和空洞卷积进行组合,认为大的卷积应该有更大的感受野. CBAM:空间和通道的注意力机制 SPP: Spatial Pyram ...
- Springboot日志LOGO改变和设计
每次启动Springboot的时候,SpringBoot都会打印一个LOGO,那么这个LOGO是可以关闭和改变的. 1.关闭Springboot的LOGO 2.改变Springboot的日志LOGO ...
- C#开发笔记之02-什么时候使用OnXXX方法,这种命名是什么意思?
C#开发笔记概述 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/958 访问. 你也许经常会看到别人写的代码里有OnXX ...
- 如何实现字符串转换成整数(实现atoi内置函数)?
题目描述 输入一个由数字组成的字符串,把它转换成整数并输出.例如:输入字符串"123",输出整数123. 给定函数原型int StrToInt(const char *str) , ...