P1081 [NOIP 2012 提高组] 开车旅行 题解
前言
爆肝到半夜,中间假了一次,最终调过了两个样例,交上去过了。
题解
思路
首先进行预处理。
用一种你喜欢的数据结构维护每个城市的海拔,容易求出从每个城市出发,小 \(A\) 和小 \(B\) 开一天能到达的城市。
因为小 \(A\) 开一天,小 \(B\) 开一天,所以设每两天为一个周期。用一个倍增数组 \(f_{i,j}\) 维护从第 \(i\) 个城市出发,行驶 \(2^j\) 个周期,能到达的城市,用数组维护这段路程的长度、小 \(A\) 开的路程和小 \(B\) 开的路程。
对于第一个问题,我们枚举每一个城市,通过求出从这里出发所能到达最远的城市,即可得到小 \(A\) 和小 \(B\) 分别行驶的路程,就能在 \(O(n\log{n})\) 的时间内得到答案。
对于第二个问题,我们仿照上一问直接求解,时间复杂度 \(O(m\log{n})\)。
实现
关于预处理,由于海拔各不相同,所以可选的数据结构较多。笔者使用 vector,每次用 lower_bound 查找,倒着扫一遍就出来了。
因为要求第二近的,所以在需要在 vector 中遍历每个城市前后两个城市的海拔。
关于求解,需要注意,可能真正最远的城市不一定是通过 \(f_{i,j}\) 数组求出的城市,需要判断能不能让小 \(A\) 再走一天。
剩下的细节看代码。
代码
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define N 100005
#define abs(x) ((x)>0?(x):-(x))
int n,m,a[N];
std::vector<int> vc;
int d[N],sd[N];
int f[N][22],g[N][22],ga[N][22],gb[N][22];
int dis(int x,int y)
{
if(x==-1||y==-1) return 1e9;
return abs(a[x]-a[y]);
}
int li[N],b[N];
bool cmp(int x,int y) {return a[x]<a[y];}
void dmin(int k,int l,int r)
{
int mi=-1;
if(l<0) l=0;
if(r>=vc.size()) r=vc.size()-1;
for(int i=l;i<=r;i++)
if(mi==-1||dis(k,li[vc[i]])<dis(k,mi)) mi=li[vc[i]];
if(mi==-1) {d[k]=sd[k]=-1;return;}
d[k]=mi;int mi2c=-1;
for(int i=l;i<=r;i++) if(li[vc[i]]!=mi&&(mi2c==-1||dis(k,li[vc[i]])<dis(k,mi2c))) mi2c=li[vc[i]];
if(mi2c==-1) sd[k]=-1;
else sd[k]=mi2c;
}
void getd()
{
for(int i=1;i<=n;i++) li[i]=i;
std::sort(li+1,li+n+1,cmp);
for(int i=1;i<=n;i++) b[li[i]]=i;
for(int i=n;i>=1;i--)
{
if(i<n)
{
int pos=lower_bound(vc.begin(),vc.end(),b[i])-vc.begin()-1;
dmin(i,pos-1,pos+3);
}
vc.insert(lower_bound(vc.begin(),vc.end(),b[i]),b[i]);
}
d[n]=-1,sd[n]=sd[n-1]=-1;
}
int main()
{
memset(f,0,sizeof(f));
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
getd();
for(int i=1;i<=n;i++)
{
if(sd[i]!=-1) f[i][0]=d[sd[i]];
else f[i][0]=-1;
ga[i][0]=dis(i,sd[i]);
gb[i][0]=dis(sd[i],d[sd[i]]);
g[i][0]=ga[i][0]+gb[i][0];
}
for(int i=1;(1<<i-1)<=n;i++) for(int j=1;j<=n;j++)
{
if(f[j][i-1]!=-1)
{
f[j][i]=f[f[j][i-1]][i-1];
g[j][i]=g[j][i-1]+g[f[j][i-1]][i-1];
ga[j][i]=ga[j][i-1]+ga[f[j][i-1]][i-1];
gb[j][i]=gb[j][i-1]+gb[f[j][i-1]][i-1];
}
else
{
f[j][i]=-1;
g[j][i]=ga[j][i]=gb[j][i]=1e9;
}
}
int x0;
scanf("%d",&x0);
int ma=1e9,mb=1,mi=-1;
for(int i=1;i<=n;i++)
{
int s=i,sum=0,sa=0,sb=0;
for(int j=20;j>=0;j--) if(f[s][j]>0&&sum+g[s][j]<=x0)
sum+=g[s][j],sa+=ga[s][j],sb+=gb[s][j],s=f[s][j];
if(s<n-1&&sum+dis(s,sd[s])<=x0) sa+=dis(s,sd[s]);
if(mi==-1||1ll*ma*sb>1ll*mb*sa) ma=sa,mb=sb,mi=i;
if((sb||mi==-1)&&1ll*ma*sb==1ll*mb*sa&&a[i]>a[mi]) mi=i;
}
printf("%d\n",mi);
scanf("%d",&m);
while(m--)
{
int s,x;
scanf("%d%d",&s,&x);
int sum=0,sa=0,sb=0;
for(int j=20;j>=0;j--) if(f[s][j]>0&&sum+g[s][j]<=x)
sum+=g[s][j],sa+=ga[s][j],sb+=gb[s][j],s=f[s][j];
if(s<n-1&&sum+dis(s,sd[s])<=x) sa+=dis(s,sd[s]);
printf("%d %d\n",sa,sb);
}
}
\]
P1081 [NOIP 2012 提高组] 开车旅行 题解的更多相关文章
- noip 2012 提高组 day2 部分题解
这道题有多种解法,我用的是扩展欧几里得算法求到的答案 #include<iostream> #include<fstream> #include<cstdio> u ...
- [NOIP2012提高组]开车旅行
题目:洛谷P1081.Vijos P1780.codevs1199. 题目大意:有n座海拔高度不相同的城市(编号1~n),两城市的距离就是两城市海拔之差.规定每次只能从编号小的城市走到编号大的城市. ...
- noip 2013 提高组 Day2 部分题解
积木大赛: 之前没有仔细地想,然后就直接暴力一点(骗点分),去扫每一高度,连到一起的个数,于是2组超时 先把暴力程序贴上来(可以当对拍机) #include<iostream> #incl ...
- Vigenère 密码NOIP 2012 提高组 第一天 第一题
题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南 ...
- NOIP 2001 提高组 题解
NOIP 2001 提高组 题解 No 1. 一元三次方程求解 https://vijos.org/p/1116 看见有人认真推导了求解公式,然后猥琐暴力过的同学们在一边偷笑~~~ 数据小 暴力枚举即 ...
- NOIP 2008提高组第三题题解by rLq
啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...
- NOIP 2014 提高组 题解
NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...
- 最优贸易 NOIP 2009 提高组 第三题
题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...
- 【NOIP2015模拟11.5】JZOJ8月5日提高组T3 旅行
[NOIP2015模拟11.5]JZOJ8月5日提高组T3 旅行 题目 若不存在第\(k\)短路径时,输出"Stupid Mike" 题解 题意 给出一个有\(n\)个点的树 问这 ...
- noip 2014 提高组初赛
noip 2014 提高组初赛 一. TCP协议属于哪一层协议( ) A. 应用层 B. 传输层 C. 网络层 D. 数据链路层 B TCP(传输控制协议) 若有变量int a; float: x, ...
随机推荐
- Blazor 组件库 BootstrapBlazor 中EditorForm组件介绍
组件介绍 EditorForm 组件是一个非常实用的组件,当进行数据编辑时,仅需要将 Model 属性赋值即可. 绑定模型默认自动生成全部属性,可以通过设置 AutoGenerateAllItem 更 ...
- Codeforces Round #826 (Div
Codeforces Round #826 (Div. 3) Minimize the Thickness 给定数组a,要求将数组a分成若干个子序列,并且使得每个子序列中的元素和都相等,设这些子序列中 ...
- ZCMU-1120
就这样 #include<cmath> #include<cstdio> #include<iostream> using namespace std; int m ...
- ecognition server注意事项
1.4002端口是节点管理界面,默认密码admin. 2.8184端口是任务管理界面. 3.节点在线状态下,查看提交的影像矢量路径是否正确. 4.看服务器读取各个文件是否有误. 5.用develope ...
- 【Amadeus原创】SQL Server数据库备份、差异备份、日志备份脚本
1,sp脚本 USE [master] GO /****** Object: StoredProcedure [dbo].[sp_BackupDatabase] Script Date: 2021/1 ...
- 第36次ccf-csp题解(思维)
比赛链接 https://sim.csp.thusaac.com/contest/36/home 比赛感受 这会刚打完上海icpc,比起区域赛的题,这个简单太多了. 感受还不错,写的很顺手.除了第 ...
- function keyword is non-standard. Delete it.
SC2112 – ShellCheck Wiki See this page on GitHub function keyword is non-standard. Delete it. Proble ...
- Shell三元表达式
Shell三元表达式 shell能否实现三元表达式呢?像下面这样: int a = (b == 5) ? c : d; 实现方法: a=$([ "$b" == 5 ] & ...
- Qt编写物联网管理平台32-表格数据
一.前言 用表格来展示采集到的数据,是很多组态系统中最常见的方法,一个表格能够展示的数据特别多,在本系统中,默认做的也是通过表格的形式来展示数据,目前是将所有的设备放在一个表格中,后期可能按照不同控制 ...
- Qt编写的项目作品5-物联网管理平台
一.功能特点 1 软件模块 设备监控模块,包括数据监控(表格形式展示).设备面板(面板形式展示).地图监控(地图形式展示).曲线监控(曲线形式展示). 数据查询模块,包括报警记录.运行记录.操作记录. ...