题意:P6375 「StOI-1」小 Z 的旅行

给定一座山,每座山有一个高度,只能向更低的山走或者向高度相同的山走,要求不能向高度相同的山连续走两次,不能原地不动。

每次走的权值都是两座山之间的坐标差的绝对值。走的山会从所有可以走的山中等概率随机选。求从最高的山到最低的山的期望权值。保证最高与最低的山唯一。

思路

看到期望,显然考虑 DP。

发现从高到低不好弄,因此考虑从最低的山依次向最高的山转移。这样我们显然先将点按山的高度从小到大排序,然后按顺序依次考虑。

由于有不能连续走的要求,因此我们设 \(f_{i,0/1}\) 表示从第 \(i\) 个点开始,能否再连续走高度相同的山,走到高度最低的山的期望权值。其中 \(f_{i,0}\) 表示不能再连续走,\(f_{i,1}\) 反之。

然后发现 \(f_{i,0}\) 只能从比其低的山转移而来,而转移后就一定可以再连续走,因此有转移:

\[f_{i,0}=\frac{\sum_{h_j<h_i} f_{j,1}+|x_i-x_j|}{\sum_j [h_j<h_i]}
\]

其中 \(x_i\) 表示排完序后第 \(i\) 个点在序列中的原坐标

由于我们已经按高度排序,因此发现这就是一个前缀和而已,高度比 \(h_i\) 小的点数也是好求的。因此我们设 \(num0_i\) 表示高度低于 \(h_i\) 的点数。

然后对于 \(f_{i,1}\),其有概率走到高度比 \(h_i\) 低的点,这时同样也是从 \(f_{j,1}\) 转移而来,也有概率走到比 \(h_i\) 高的点,这时由于不能连续走因此就要从 \(f_{j,0}\) 转移而来。

注意还要除以总的方案数。我们同样定义一个 \(num1_i\) 表示高度小于等于 \(h_i\) 的点数。综上,有转移:

\[f_{i,1}=\frac{(\sum_{h_j<h_i} f_{j,1}+|x_i-x_j|) + (\sum_{h_j=h_i}f_{j,0}+|x_i-x_j|)}{num1_i}
\]

可以发现分子上第一个括号的形式与 \(f_{i,0}\) 是一样的,因此可以化简一下。注意要将选到比 \(h_i\) 低的情况数乘上。化简后有转移:

\[f_{i,1}=\frac{f_{i,0}\times num0_i + (\sum_{h_j=h_i}f_{j,0}+|x_i-x_j|)}{num1_i}
\]

可以发现对于两个转移,我们都可以将 \(f_j,0/1\) 与绝对值的计算分开处理。显然排序后对于 \(f\) 的求和仍然是前缀和就可以解决的。

然后我们就只需要处理距离的绝对值了。由于整个序列都不会变,因此我们可以将这个距离预处理出来。

我们可以通过树状数组从左到右扫一遍来做。具体而言,应另一篇题解的提醒,可以去做这种处理绝对值的 模板题

需要注意的是,我么需要处理两种权值,一种是到所有 \(h_j<h_i\) 的 \(j\) 的权值,另一种是到所有 \(h_j=h_i\) 的 \(j\) 的权值,我们分别记为 \(dis0_i\) 和 \(dis1_i\)。

code

实现的话我没有用离散化,而是将所有 \(h\) 相同的点一起转移。个人感觉这样思路比较清晰。

具体看代码吧。代码略有压行。(?)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=998244353,N=5e5+7;
int n,dis0[N],dis1[N],num0[N],num1[N],f[N][2],tmpsum[N],tmpcnt[N];
struct node{int x,h;}a[N];
struct edge{ //树状数组
int tr[N];
void modify(int x,int w){while(x<=N-5)(tr[x]+=w)%=p,x+=x&(-x);}
int query(int x){int res=0;while(x) (res+=tr[x])%=p,x-=x&-x;return res;}
}sum,cnt; //分别记前缀坐标的和以及前缀坐标的个数
bool cmp(node x,node y){return x.h<y.h;}
int ksm(int x,int k){
int res=1;x%=p;
while(k){if(k&1) res=res*x%p;x=x*x%p,k>>=1;}
return res;
}
#define inv(x) (ksm(x,p-2))
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n;for(int i=1,h;i<=n;i++) cin>>h,a[i]={i,h};
sort(a+1,a+n+1,cmp);int tmp=0;
for(int l=1;l<=n;){
int r=l,z=0;
while(a[r].h==a[r+1].h) ++r; //注意到高度小于的点数就是 l-1,等于的点数就是 r-l。(注意不能走到自己)
for(int i=l;i<=r;i++){
int sum0=sum.query(a[i].x)%p,cnt0=cnt.query(a[i].x);tmpsum[i]=sum0,tmpcnt[i]=cnt0;
num0[i]=l-1;dis0[i]=(cnt0*a[i].x%p-sum0 + (tmp-sum0-(l-1-cnt0)*a[i].x%p)+p)%p;//坐标小的与大的分开计算
}
for(int i=l;i<=r;i++) sum.modify(a[i].x,a[i].x),cnt.modify(a[i].x,1),z+=a[i].x;
//先求出严格小于的再将权值相同的插入进树状数组,同时统计权值相同的权值和
for(int i=l;i<=r;i++){
int sum1=(sum.query(a[i].x-1)%p-tmpsum[i]+p)%p,cnt1=(cnt.query(a[i].x-1)-tmpcnt[i]+p)%p;//这里将总的减去之前记录的高度小于的就是高度等于的信息
num1[i]=r-1;dis1[i]=(cnt1*a[i].x%p-sum1 + z-a[i].x-sum1-(r-l-cnt1)*a[i].x+p)%p;
}
l=r+1;tmp+=z;
}
f[1][0]=f[1][1]=0;int tmp0=0,tmp1=0;
for(int l=2;l<=n;){
int r=l,z=0,y=0;while(a[r].h==a[r+1].h) ++r;
for(int i=l;i<=r;i++) f[i][0]=(tmp1+dis0[i])%p*inv(l-1)%p,z=(z+f[i][0])%p;
for(int i=l;i<=r;i++) f[i][1]=(f[i][0]*(l-1)%p*inv(r-1)%p+(z-f[i][0]+dis1[i]+p)%p*inv(r-1)%p)%p,y=(y+f[i][1])%p;
(tmp0+=z)%=p,(tmp1+=y)%=p;
l=r+1;
}
cout<<f[n][0]<<'\n';return 0;
return 0;
}

P6375 「StOI-1」小Z的旅行 题解的更多相关文章

  1. 「国家集训队」小Z的袜子

    「国家集训队」小Z的袜子 传送门 莫队板子题. 注意计算答案的时候,由于分子分母都要除以2,所以可以直接约掉,这样在开桶算的时候也方便一些. 参考代码: #include <algorithm& ...

  2. GDOI2015小Z的旅行路线

    GDOI2015小Z的旅行路线 题意: \(n\)个点的无根树,边上有权值. \(q\)个询问\(s\)和\(s\),问从\(s\)出发,找一条最长路(不经过重复点),保证路径上所有边边权不超过\(x ...

  3. 小Z的袜子(题解)(莫队)

    小Z的袜子(题解)(莫队) Junlier良心莫队 题目 luoguP1494 [国家集训队]小Z的袜子 code #include<bits/stdc++.h> #define lst ...

  4. 小Z的袜子 题解报告【莫队】

    Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只 ...

  5. BZOJ2038:[2009国家集训队]小Z的袜子——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2038 Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找 ...

  6. 【LOJ】#2122. 「HEOI2015」小 Z 的房间

    题解 又是一道取模不给质数的毒瘤矩阵树题 不会写分数类--然后发现了网上过于神仙的题解类似与辗转相除的这样把某一个位置消成0 orz 代码 #include <bits/stdc++.h> ...

  7. LG4111/LOJ2122 「HEOI2015」小Z的房间 矩阵树定理

    问题描述 LG4111 题解 矩阵树定理板子题. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace std; #defin ...

  8. 「10.14」小P的2048(模拟)·小P的单调数列(性质,DP)·小P的生成树(乱搞)

    A. 小P的2048 模拟.....又没啥可说的,以后要认真打打模拟题了... B. 小P的单调数列 考场$n^2log(n)$的SB思路有人听吗 正解当然不是这样, 事实上我们每次选取的只有一段区间 ...

  9. 题解 「THUPC 2017」小 L 的计算题 / Sum

    题目传送门 题目大意 给出 \(a_{1,2,...,n}\),对于 \(\forall k\in [1,n]\) ,求出: \[\sum_{i=1}^{n}a_i^k \] \(n\le 2\tim ...

  10. LOJ 2409「THUPC 2017」小 L 的计算题 / Sum

    思路 和玩游戏一题类似 定义\(A_k(x)=\sum_{i=0}^\infty a_k^ix^i=\frac{1}{1-a_kx}\) 用\(\ln 'x\)代替\(\frac{1}{x}\), 所 ...

随机推荐

  1. 百万架构师第三十九课:RabbitMq:Linux安装RabbitMq|JavaGuide

    来源:https://javaguide.net RPM包安装RabbitMQ RabbitMQ的安装非常简单,由于RabbitMQ依赖于Erlang,所以需要先安装Erlang,解决依赖关系后,就可 ...

  2. Python中requests库的安装

    这篇博客指导读者如何通过管理员权限的CMD命令行,进入Python主目录并使用pip安装requests库.在PyCharm中,如果IDE未检测到requests,用户需要在此安装,或者考虑更新Pyt ...

  3. yarn的安装与配置(秒懂yarn用法)

    安装和配置Yarn可以通过以下步骤完成: 安装Node.js:首先,确保已经安装了Node.js.可以通过在终端中运行node -v来检查是否已安装.如果没有安装,可以从Node.js官方网站(htt ...

  4. postgresql使用for循环

    开发过程中经常需要制造一些测试数据,sqlserver等数据库都有循环执行语句的方式,postgresql也可以使用for循环插入数据 do $$ begin for tt in 1..99 loop ...

  5. AI 智能体引爆开源社区「GitHub 热点速览」

    最近很火的 Manus 智能体是一款将你的想法转化为行动的工具,能够处理生活中的各种任务.一经发布便迅速走红,并间接引爆了开源社区. 这也导致上榜的全是 AI 智能体开源项目,比如无需邀请码的开源版 ...

  6. 三分钟构建高性能WebSocket服务 | 超优雅的Springboot整合Netty方案

    前言 每当使用SpringBoot进行Weboscket开发时,最容易想到的就是spring-boot-starter-websocket(或spring-websocket).它可以让我们使用注解, ...

  7. hexo 图片添加水印(png, jpeg, jpg, gif)

    文章同步发布:https://blog.jijian.link/2020-04-21/hexo-watermark/ 本文折腾 hexo 图片添加水印功能,大部分代码沿用: nodejs 图片添加水印 ...

  8. 入口函数与包初始化:Go程序的执行次序

    前言 我们可能经常会遇到这样一个问题:一个 Go 项目中有数十个 Go 包,每个包中又有若干常量.变量.各种函数和方法,那 Go 代码究竟是从哪里开始执行的呢?后续的执行顺序又是什么样的呢? 事实上, ...

  9. PVE虚拟平台常用简明操作,三分钟搞定虚拟机更换安装配置

    Proxmox Virtual Environment是一个基于QEMU/KVM和LXC的开源服务器虚拟化管理解决方案,本文简称PVE,与之相类似的虚拟化平台是VMWARE的ESXi虚拟平台,相较于商 ...

  10. 青岛oj集训5

    Floyd算法--全源最短路 cerr:标准输出错误流:不会输出到freopen制定的out文件中,而是会输出到错误文件中. 提交上去无论加不加freopen,哪怕是提交到洛谷,也只是比较out文件中 ...