luoguP1081 开车旅行 题解(NOIP2012)
这道题是真滴火!(一晚上加一节信息课!)
先链接一下题目:luoguP1081 开车旅行
首先,这个预处理就极其变态,要与处理出每一个点往后走A会去哪里,B会去哪里。而且还必须O(nlogn)给它跑出来,反正这就要了我好久好久的时间,还没想出来!那么我们来慎重思考一下:
1.既然要让我们这么快的时间内把一个点东边的高度最近和次近找出来,只能考虑先排序。那我们就先让它以高度为关键字排一遍序,肯定还是要记录一下原先的序号的。
2.模拟一下,如果我们要找第一个点(最西边的点)的预处理,那不就是在排完序的数组中找一下它左边两个和它右边两个再比较一下找出最近和次近(这个应该不难想)。然后,如果再找第二个点的预处理,第一个点显然有可能会干扰到它,所以处理完第一个点之后我们考虑把它“删”掉,这就可以用双向链表来维护了(啦啦啦!别以为这个东西很NB,其实就是用一个l,r来记录i点排序之后左边和右边的第一个东边城市,啦啦啦!),实现还是很困难的//...冷笑...\\
对应Prepare(双向链表部分在solve()里面)函数!!!
3.预处理完我们就要维护x范围内的a开的距离和b开的距离了。其实我是想了很久之后才知道怎么用倍增的(当然是看的标签之后才知道要用倍增的(我太菜了!!!))。不管了,直接倍增吧...
f[i][j]表示从i城市出发走2*2^j(就是a,b都走2^j)步到达的城市编号。
disA[i][j]表示从i城市出发走2*2^j(就是a,b都走2^j)步a开了多远。
disB[i][j]表示从i城市出发走2*2^j(就是a,b都走2^j)步b开了多远。
对应Bz函数!!!最后倍增的查找对应getab函数!!!
4.一个小细节:因为我们是直接倍增跳a,b一起开(如上j),所以找a,b各走了多远时最后还要特判一下a是否还可以在开一轮。
上代码:
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<ctime>
#include<queue>
#include<stack>
#define lst long long
#define rg register
#define N 100050
#define Inf 2147483647
using namespace std; int n,m,X0,ans=n;
struct CITY{
lst v;
int num,l,r;
}ljl[N];
int back[N],go[N],nA[N],nB[N];
int f[N][];
lst disA[N][],disB[N][],a,b;
double minn=; inline lst read()
{
rg lst s=,m=;char ch=getchar();
while(ch!='-'&&(ch<''||ch>''))ch=getchar();
if(ch=='-')m=-,ch=getchar();
while(ch>=''&&ch<='')s=(s<<)+(s<<)+ch-'',ch=getchar();
return s*m;
} inline int cmp(rg const CITY &a,rg const CITY &b){return a.v<b.v;}
inline int dis(rg int p,rg int q){return abs(ljl[p].v-ljl[q].v);} inline int pd(rg int x,rg int y,rg int now)//x小返回1,y小返回0
{
if(!x)return ;//x不存在
if(!y)return ;//y不存在
return dis(x,now)<=dis(y,now);//返回小一些的
} inline void solve(rg int tt,rg int now)
{
rg int ll=ljl[now].l,rr=ljl[now].r;
if(pd(ll,rr,now))//左边离得近一些
if(pd(ljl[ll].l,rr,now))//左边的左边离得近一些
nB[tt]=back[ll],nA[tt]=back[ljl[ll].l];
else//右边离得近一些
nB[tt]=back[ll],nA[tt]=back[rr];
else//右边离得近一些
if(pd(ll,ljl[rr].r,now))//左边离得近一些
nB[tt]=back[rr],nA[tt]=back[ll];
else//右边的右边离得近一些
nB[tt]=back[rr],nA[tt]=back[ljl[rr].r];
if(ll)ljl[ll].r=rr;
if(rr)ljl[rr].l=ll;
} inline void Prepare()
{
n=read();
for(rg int i=;i<=n;++i)ljl[i].v=read(),ljl[i].num=i;
sort(ljl+,ljl+n+,cmp);//以高度为关键字排序
for(rg int i=;i<=n;++i)back[i]=ljl[i].num,go[back[i]]=i;//排完序之后的元素在原数组中的位置
for(rg int i=;i<=n;++i)ljl[i].l=i-,ljl[i].r=i+;
ljl[].l=ljl[n].r=;
for(rg int i=;i<=n;++i)solve(i,go[i]);
} inline void Bz()
{
for(rg int i=;i<=n;++i)
{
f[i][]=nB[nA[i]];
disA[i][]=dis(go[i],go[nA[i]]);
disB[i][]=dis(go[nA[i]],go[f[i][]]);
}
for(rg int j=;j<=;++j)
for(rg int i=;i<=n;++i)
{
f[i][j]=f[f[i][j-]][j-];
disA[i][j]=disA[i][j-]+disA[f[i][j-]][j-];
disB[i][j]=disB[i][j-]+disB[f[i][j-]][j-];
}
/* for(rg int i=1;i<=n;++i)
for(rg int j=0;j<=3;++j)
{
printf(" f[%d][%d]=%d\n",i,j,f[i][j]);
printf("disA[%d][%d]=%lld\n",i,j,disA[i][j]);
printf("disB[%d][%d]=%lld\n",i,j,disB[i][j]);
}
*/} inline void getab(rg int x,rg int now)
{
a=b=;
for(rg int i=;i>=;--i)
if(f[now][i]&&(a+b+disA[now][i]+disB[now][i]<=x))
a+=disA[now][i],b+=disB[now][i],now=f[now][i];
if(nA[now]&&a+b+disA[now][]<=x)a+=disA[now][];
} int main()
{
Prepare();//预处理左右A,B的方案
// for(rg int i=1;i<=n;++i)printf("nA[%d]=%d nB[%d]=%d\n",i,nA[i],i,nB[i]);
Bz();//处理倍增
X0=read(),m=read();
for(rg int i=;i<=n;++i)
{
getab(X0,i);
if(b&&1.0*a/b<minn)
minn=1.0*a/b,ans=i;
}
printf("%d\n",ans);
for(rg int i=;i<=m;++i)
{
rg int s=read(),x=read();
getab(x,s);
printf("%lld %lld\n",a,b);
}
return ;
}
ojbk!!!
luoguP1081 开车旅行 题解(NOIP2012)的更多相关文章
- 开车旅行 【NOIP2012 D1T3】
开车旅行 [NOIP2012 D1T3] 倍增 首先令\(a[i]\)表示从i出发最近的城市下标,\(b[i]\)表示从i出发第二近的城市下标 可以维护一个\(\text{set<pair< ...
- noip2012开车旅行 题解
题目大意: 给出n个排成一行的城市,每个城市有一个不同的海拔.定义两个城市间的距离等于他们的高度差的绝对值,且绝对值相等的时候海拔低的距离近.有两个人轮流开车,从左往右走.A每次都选最近的,B每次都选 ...
- 刷题总结——开车旅行(NOIP2012 set+倍增)
题目: 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城 ...
- 【NOIP2012】开车旅行(倍增)
题面 Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 ...
- Luogu 1081 【NOIP2012】开车旅行 (链表,倍增)
Luogu 1081 [NOIP2012]开车旅行 (链表,倍增) Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已 ...
- Cogs 1264. [NOIP2012] 开车旅行(70分 暴力)
1264. [NOIP2012] 开车旅行 ★★☆ 输入文件:drive.in 输出文件:drive.out 简单对比时间限制:2 s 内存限制:128 MB [题目描述] 小A 和小 ...
- P1081 [NOIP2012]开车旅行[倍增]
P1081 开车旅行 题面较为啰嗦.大概概括:一个数列,只能从一个点向后走,两种方案:A.走到和自己差的绝对值次小的点B.走到和自己差的绝对值最小点:花费为此差绝对值:若干询问从规定点向后最多花 ...
- [NOIP2012提高组]开车旅行
题目:洛谷P1081.Vijos P1780.codevs1199. 题目大意:有n座海拔高度不相同的城市(编号1~n),两城市的距离就是两城市海拔之差.规定每次只能从编号小的城市走到编号大的城市. ...
- CH5701 开车旅行
题意 5701 开车旅行 0x50「动态规划」例题 描述 小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ...
随机推荐
- 安装运行谷歌开源的TensorFlow Object Detection API视频物体识别系统
Linux安装 参照官方文档:https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/inst ...
- 关于使用itext转Html为pdf添加css样式的问题
使用的jar文件 xmlworker-5.5.11.jar itextpdf-5.5.11.jar 下载地址:https://pan.baidu.com/s/1i5AIBvZ 以下为测试代码 pack ...
- 使用Python和AWK两种方式实现文本处理的长拼接案例
最近由于业务系统新需求的需要,我们平台需要将供应商G提供一类数据转换格式后提供给客户K.比较头疼是供应商G提供的数据都是在Windows下使用Excel存储的,而客户K先前与我们相关对接人员商定的数据 ...
- php内置函数分析之trim()
官方手册中: 类似函数还有两个:ltrim() 和 rtrim().分别处理字符串的左侧.右侧. trim()的具体实现位于:ext/standard/string.c /* {{{ proto st ...
- [BZOJ] 地精部落
问题描述 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为 N 的山脉 H 可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi,其中 Hi ...
- Redis之数据类型
一.概念: Redis:一个开源.支持网络.基于内存.键值对存储数据库. 特点:它可以支持多种数据类型. 二.数据类型 1)Redis String 具体说明: 一般的普通的k到v一个映射是Strin ...
- python绘制图的度分布柱状图, draw graph degree histogram with Python
图的度数分布 import collections import matplotlib.pyplot as plt import networkx as nx G = nx.gnp_random_gr ...
- 英语单词deploy
来源——https://www.docker.com/ Leading companies rely on our container platform to build, manage and se ...
- win7 开机,或重启自动启动 该文件下的
win7 开机,或重启自动启动 该文件下的: 把桌面上快捷键放入文件内就行 C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start ...
- asp.net大文件断点续传
以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传 ...