开车旅行(算法竞赛进阶指南,倍增优化 DP)

2024-03-30 13:48

本文主要是介绍开车旅行(算法竞赛进阶指南,倍增优化 DP),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.题目链接:

开车旅行

二.题目大意:

中文题有点长,就不误导大家了...

三.分析:

先预处理出一下量:

ga[i]:从城市 i 出发,小 A 下一步要到的城市.

gb[i]:从城市 i 出发,小 B 下一步要到的城市.

f[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后到达的城市编号.

da[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后,小 A 走过的距离.

db[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后,小 B 走过的距离. 

求出上述结果后,我们就可以利用倍增以 O(log_2x) 的时间复杂度求出小 A 与 小 B 分别走的距离.

下面给出上述结果的求解方法.

ga[i]:从城市 i 出发,小 A 下一步要到的城市.

gb[i]:从城市 i 出发,小 B 下一步要到的城市.

倒序枚举城市 i,二分可以找出第一个高度大于等于城市 i 的城市,左右寻找即可.

void init_g()
{set < pair <ll, int> > st;st.emplace(make_pair(inf, 0));st.emplace(make_pair(inf + 1, 0));st.emplace(make_pair(-inf, 0));st.emplace(make_pair(-inf - 1, 0));for(int i = n; i >= 1; --i){auto j = st.lower_bound(make_pair(h[i], i));--j, --j;ll mn = inf, sm = inf;int mni, smi;for(int k = 0; k < 4; ++k){auto p = *j;ll d = (ll)abs(p.first - h[i]);if(d < mn){sm = mn, smi = mni;mn = d, mni = p.second;}else if(d < sm){sm = d, smi = p.second;}++j;}ga[i] = smi, gb[i] = mni;st.emplace(make_pair(h[i], i));}
}

 

f[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后到达的城市编号.

i = 0:f[0][j][0] = ga[j], f[0][j][1] = gb[j];

i = 1:f[1][j][k] = f[0, f[0][j][0], 1 - k];

i > 1:f[i][j][k] = f[i - 1][f[i - 1][j][k]][k];

void init_f()
{for(int j = 1; j <= n; ++j){f[0][j][0] = ga[j];f[0][j][1] = gb[j];}for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){f[1][j][k] = f[0][f[0][j][k]][1 - k];}}for(int i = 2; i < N; ++i){for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){f[i][j][k] = f[i - 1][f[i - 1][j][k]][k];}}}
}

 

 da[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后,小 A 走过的距离.

 db[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后,小 B 走过的距离. 

首先定义函数 get_dist(i, j) = abs(h[i] - h[j]);

i = 0:da[0][j][0] = get_dist(j, ga[j]), da[0][j][1] = 0;

           db[0][j][0] = 0, db[0][j][1] = get_dist(j, gb[j]);

i = 1:da[1][j][k] = da[0][j][k] + da[0][f[0][j][k]][1 - k];

          db[1][j][k] = db[0][j][k] + db[0][f[0][j][k]][1 - k];

i > 1:da[i][j][k] = da[i - 1][j][k] + da[i - 1][f[i - 1][j][k]][k];

          db[i][j][k] = db[i - 1][j][k] + db[i - 1][f[i - 1][j][k]][k];

int get_dist(int i, int j)
{return (int)abs(h[i] - h[j]);
}void init_d()
{for(int j = 1; j <= n; ++j){da[0][j][0] = get_dist(j, ga[j]), da[0][j][1] = 0;db[0][j][1] = 0, db[0][j][1] = get_dist(j, gb[j]);}for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){da[1][j][k] = da[0][j][k] + da[0][f[0][j][k]][1 - k];db[1][j][k] = db[0][j][k] + db[0][f[0][j][k]][1 - k];}}for(int i = 2; i < N; ++i){for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){da[i][j][k] = da[i - 1][j][k] + da[i - 1][f[i - 1][j][k]][k];db[i][j][k] = db[i - 1][j][k] + db[i - 1][f[i - 1][j][k]][k];}}}
}

 

四.代码实现:

#include <bits/stdc++.h>
using namespace std;typedef long long ll;const int M = (int)1e5;
const int N = (int)17;
const ll inf = 0x3f3f3f3f3f3f3f3f;int n;
int h[M + 5];
int ga[M + 5], gb[M + 5];
int f[N][M + 5][2];
ll da[N][M + 5][2], db[N][M + 5][2];void read()
{scanf("%d", &n);for(int i = 1; i <= n; ++i)scanf("%d", &h[i]);
}void init_g()
{set < pair <ll, int> > st;st.emplace(make_pair(inf, 0));st.emplace(make_pair(inf + 1, 0));st.emplace(make_pair(-inf, 0));st.emplace(make_pair(-inf - 1, 0));for(int i = n; i >= 1; --i){auto j = st.lower_bound(make_pair(h[i], i));--j, --j;ll mn = inf, sm = inf;int mni, smi;for(int k = 0; k < 4; ++k){auto p = *j;ll d = (ll)abs(p.first - h[i]);if(d < mn){sm = mn, smi = mni;mn = d, mni = p.second;}else if(d < sm){sm = d, smi = p.second;}++j;}ga[i] = smi, gb[i] = mni;st.emplace(make_pair(h[i], i));}
}void init_f()
{for(int j = 1; j <= n; ++j){f[0][j][0] = ga[j];f[0][j][1] = gb[j];}for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){f[1][j][k] = f[0][f[0][j][k]][1 - k];}}for(int i = 2; i < N; ++i){for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){f[i][j][k] = f[i - 1][f[i - 1][j][k]][k];}}}
}int get_dist(int i, int j)
{return (int)abs(h[i] - h[j]);
}void init_d()
{for(int j = 1; j <= n; ++j){da[0][j][0] = get_dist(j, ga[j]), da[0][j][1] = 0;db[0][j][1] = 0, db[0][j][1] = get_dist(j, gb[j]);}for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){da[1][j][k] = da[0][j][k] + da[0][f[0][j][k]][1 - k];db[1][j][k] = db[0][j][k] + db[0][f[0][j][k]][1 - k];}}for(int i = 2; i < N; ++i){for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){da[i][j][k] = da[i - 1][j][k] + da[i - 1][f[i - 1][j][k]][k];db[i][j][k] = db[i - 1][j][k] + db[i - 1][f[i - 1][j][k]][k];}}}
}void init()
{init_g();init_f();init_d();
}void cal(int s, int x, int& la, int& lb)
{la = lb = 0;for(int i = N - 1; i >= 0; --i){if(f[i][s][0] && la + lb + da[i][s][0] + db[i][s][0] <= x){la += da[i][s][0];lb += db[i][s][0];s = f[i][s][0];}}
}void work()
{int s, x;scanf("%d", &x);int la, lb;int max_h = 0, ans;double min_r = inf, r;for(int i = 1; i <= n; ++i){cal(i, x, la, lb);r = lb ? 1.0 * la / lb : inf;if(r < min_r || r == min_r && h[i] > max_h){ans = i;min_r = r;max_h = h[i];}}printf("%d\n", ans);int m;scanf("%d", &m);while((m--) > 0){scanf("%d %d", &s, &x);cal(s, x, la, lb);printf("%d %d\n", la, lb);}
}int main()
{
//    freopen("input.txt", "r", stdin);read();init();work();return 0;
}

 

这篇关于开车旅行(算法竞赛进阶指南,倍增优化 DP)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/861656

相关文章

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

Python进行JSON和Excel文件转换处理指南

《Python进行JSON和Excel文件转换处理指南》在数据交换与系统集成中,JSON与Excel是两种极为常见的数据格式,本文将介绍如何使用Python实现将JSON转换为格式化的Excel文件,... 目录将 jsON 导入为格式化 Excel将 Excel 导出为结构化 JSON处理嵌套 JSON:

深入浅出SpringBoot WebSocket构建实时应用全面指南

《深入浅出SpringBootWebSocket构建实时应用全面指南》WebSocket是一种在单个TCP连接上进行全双工通信的协议,这篇文章主要为大家详细介绍了SpringBoot如何集成WebS... 目录前言为什么需要 WebSocketWebSocket 是什么Spring Boot 如何简化 We

Python极速搭建局域网文件共享服务器完整指南

《Python极速搭建局域网文件共享服务器完整指南》在办公室或家庭局域网中快速共享文件时,许多人会选择第三方工具或云存储服务,但这些方案往往存在隐私泄露风险或需要复杂配置,下面我们就来看看如何使用Py... 目录一、android基础版:HTTP文件共享的魔法命令1. 一行代码启动HTTP服务器2. 关键参

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Redis MCP 安装与配置指南

《RedisMCP安装与配置指南》本文将详细介绍如何安装和配置RedisMCP,包括快速启动、源码安装、Docker安装、以及相关的配置参数和环境变量设置,感兴趣的朋友一起看看吧... 目录一、Redis MCP 简介二、安www.chinasem.cn装 Redis MCP 服务2.1 快速启动(推荐)2.

C语言进阶(预处理命令详解)

《C语言进阶(预处理命令详解)》文章讲解了宏定义规范、头文件包含方式及条件编译应用,强调带参宏需加括号避免计算错误,头文件应声明函数原型以便主函数调用,条件编译通过宏定义控制代码编译,适用于测试与模块... 目录1.宏定义1.1不带参宏1.2带参宏2.头文件的包含2.1头文件中的内容2.2工程结构3.条件编