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编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ...
随机推荐
- Kintex 7五兄弟
基KC705E 增强版 基于FMC接口的Xilinx Kintex-7 FPGA K7 XC7K325T PCIeX8 接口卡(136) 本板卡是Xilinx公司芯片V5系列芯片设计信号处理板卡.由一 ...
- JS删除对象中的某一属性(delete)
var obj= {} 1.JS对象添加新属性 obj.address="shenzhen" 2.JS删除对象中的某一属性(delete) var obj= { height: , ...
- lsattr 查看文件扩展属性
1. 命令功能 lsattr查看 是否有chattr设置的权限. 2. 使用范例 [root@localhost data]# lsattr resolv.conf -----a-------e- r ...
- HDU-6038 Function 思维+循环节
解法:这道题很有意思,值得一做和细细思考. 首先是我们要观察这个映射公式,他的实质是什么?其实就是b到a的循环映射,这是因为a数列和b数列都是0-n-1的排列,意味着每个数都是唯一的,那么ab的这个循 ...
- 通过反射获取方法的参数名称(JDK8以上支持)
方法的参数名,在很多时候我们是需要反射得到的.但是在java8之前,代码编译为class文件后,方法参数的类型是固定的,但参数名称却丢失了,这和动态语言严重依赖参数名称形成了鲜明对比.(java是静态 ...
- 定位公众号页面,跳转之后 vuejs 失效问题
是第一个页面的. data () { }, 写成了这样,没写返回 {} 5555~. 网页中死活可以,微信中死活不行. data () { return {} },
- CH5E26 扑克牌 (计数类DP)
$ CH~5E26~\times ~ $ 扑克牌: (计数类DP) $ solution: $ 唉,计数类DP总是这么有套路,就是想不到. 这道题我们首先可以发现牌的花色没有价值,只需要知道每种牌有 ...
- 24.mongodb可视化工具部署——2019年12月19日
2019年10月09日17:05:54 教程链接:https://blog.csdn.net/qq_32340877/article/details/79142129 项目名:adminMongo g ...
- NLP第一周
19-21周,每周学习15小时以上 基础:Python编程基础:基础的概览统计.了解线性代数:足够的时间投入. 完成9个课程项目,每个5小时-15小时 完成聊天机器人项目(40-80小时) Capst ...
- [洛谷P2296] NOIP2014 寻找道路
问题描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条 ...