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编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ...
随机推荐
- Express 2015 RC for Windows 10 安装
支持的操作系统 Windows 10 Technical Preview 硬件要求 1.6 GHz 或更快的处理器 1 GB RAM(如果在虚拟机上运行,则为 1.5 GB) 4 GB 可用硬盘空间 ...
- tac反向显示文件内容
1.命令功能 tac是cat的反向拼写功能是反向显示文件内容.cat是从文件第一行开始读取文件输出,tac是从最后一行开始读取文件并进行反向输出. 2.语法格式 tac [option] [fil ...
- No qualifying bean of type xxx' available 的一种解决方法
获取bean Class beanClass = Class.forName(event.className); FilterEvent filterEvent = (FilterEvent)Bean ...
- 前端面试题(4)JavaScript
前端面试题JavaScript(一) JavaScript的组成 JavaScript 由以下三部分组成: ECMAScript(核心):JavaScript 语言基础 DOM(文档对象模型):规定了 ...
- php中美元符号是什么意思
php中$符号是变量符号: 把$符号加上字符串,这个字符串就是一个变量名或对象名. 其实PHP采用的是C语言的语法,但是也有一些区别,$符号加上字符串,这就是一个变量名或对象名. 例如下面的代码:(推 ...
- BZOJ 1597: [Usaco2008 Mar]土地购买 动态规划 + 斜率优化
Code: #include<bits/stdc++.h> #define maxn 1000000 #define ll long long #define x(i) (b[i+1]) ...
- ubuntu 18.04下修改pip镜像源
在home/用户名/目录下创建.pip文件夹 然后cd .pip 创建pip.conf文件touch pip.conf 输入以下内容然后保存即可 [global] timeout = 6000 ind ...
- Flask学习 1创建第一个页面
#!/usr/bin/env python # encoding: utf-8 """ @version: v1.0 @author: cxa @file: hello. ...
- python requests使用登陆之后的cookie
def getcontent(self): cookie_text=r'ur=FTW; mid=WsrlLwAEAAEfpCstNyTJl-1oZa0w; ig_pr=1; ig_vh=949; cs ...
- 【运维】使用FileZilla搭建FTP服务器
一.下载Filezilla Server 官网网址:https://filezilla-project.org 二.安装Filezilla Server Filezilla Server的安 ...