题意: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. 深入解析NoSQL数据库:从文档存储到图数据库的全场景实践

    title: 深入解析NoSQL数据库:从文档存储到图数据库的全场景实践 date: 2025/2/19 updated: 2025/2/19 author: cmdragon excerpt: 通过 ...

  2. 微信小程序实现分类菜单激活状态随列表滚动而自动切换效果详解

    这篇文章主要介绍了微信小程序分类菜单激活状态跟随列表滚动自动切换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧 目录 view结构 ...

  3. docker - [03] docker原理

    题记 一.docker是怎么工作的 docker是一个CS(Client - Server)结构的系统,docker的守护进程运行在主机上,通过Socket从客户端访问. docker Server接 ...

  4. clickhouse--数据类型

    数据类型 整型 固定长度的整型,包括有符号整型或无符号整型. 整型范围(-2n-1~2n-1-1): Int8 - [-128 : 127] Int16 - [-32768 : 32767] Int3 ...

  5. vue3项目中环境变量使用技巧

    在Vue 3项目中,环境变量是管理不同环境下配置的强大工具.以下是一些关于如何在Vue 3项目中有效地定义.访问和使用环境变量的技巧,以及如何在不同环境下管理这些变量的最佳实践. 一.定义环境变量 在 ...

  6. mySql跳过行数获取多少行

    LIMIT :需要获取多少条记录 OFFSET :跳过前面的多少行记录从后面开始获取 SELECT * FROM USER LIMIT 32 OFFSET 1 只获取12行记录 跳过第一条记录 SEL ...

  7. python xlrd 读取表格 单元格值被覆盖

    代码实现顺序: 按行读取 按列读取 满足if条件 单元格值赋值给字典 实现代码: datas = []# 定义一个空列表 for i in range (3,nrows): sheet_data={} ...

  8. fs的proxy_media模式失效

    概述 freeswitch是一款简单好用的VOIP开源软交换平台. 在fs的使用过程中,某些场景只需要对rtp媒体做透传,又不需要任何处理. 在fs1.6的版本中,我们可以使用proxy_media来 ...

  9. 基础命令:dd、tar、ln、find、逻辑符号、alisa别名、md5sun校验、lrzsz文件上传下载、wget

    目录 3.0 dd读取.转换并输出数据 3.1 压缩 (tar.zip).解压缩(tar xf.unzip) 3.2 ln软硬链接 3.2.1 软链接: 3.2.2 硬链接: 3.3 find文件查找 ...

  10. C++基础学习--随记

    博客地址:https://www.cnblogs.com/zylyehuo/ 参考"C++基础与深度解析" 一.预备知识 // c++常用工具 /usr/bin/time //查看 ...