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编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ...
随机推荐
- Web学习之JS总结
银角大王武Sir的博客地址 银角大王武Sir的博客地址二 1.Javascript的作用域链 由于javascript没有块级作用域,而且每个函数作为一个作用域,如果出现嵌套函数,则就会出现作用域链 ...
- .h与.cpp
本质上没什么区别. cpp:c plus plus,就表示为c++原文件. .h文件实现的功能是声明.cpp文件中需要使用的变量.函数及宏定义等. .h文件就像是一个接口,具体的实现可以在.cpp中, ...
- 【LeetCode】按 tag 分类索引 (900题以下)
链表:https://www.cnblogs.com/zhangwanying/p/9797184.html (共34题) 数组:https://www.cnblogs.com/zhangwanyin ...
- NOIP原题板刷
update 10.11 我可能已经刷完大部分了,可是这篇blog我也不想更了 这个人很懒,做了很多题但是不想写题解,也不想更blog,所以这篇blog又咕咕了. 把从 \(1997-2017\) 近 ...
- 破坏双亲委托机制的一些情况---Tomcat和JDBC,破坏后的安全问题
采用双亲委托机制的原因 类加载器就是将字节码搬进jvm方法区的组件.我们知道,JVM识别加载进来的类是通过类加载器+类全名完成的,也就是说同一个类由不同类加载器加载进去的话就会被视为不同的类.jdk提 ...
- vue项目-本机ip地址访问
修改 在 vue项目文件夹中的 package.json scripts >dev 添加 --host 0.0.0.0 "dev": "webpack-dev-se ...
- 阿里云吴天议:云原生SDWAN 应用 构建智能化云原生SDWAN生态
2019年11月16日 SDWAN 大会在北京正式召开.阿里云网络资深产品专家吴天议先生继阿里云网络研究员祝顺民先生发表了对云原生SDWAN的进化与展望之后(原文请见https://bit.ly/2K ...
- CSS中浮动属性float及清除浮动
1.float属性 CSS 的 Float(浮动),会使元素向左或向右移动,由于浮动的元素会脱离文档流,所以它后面的元素会重新排列. 浮动元素之后的那些元素将会围绕它,而浮动元素之前的元素将不会受到影 ...
- IP释放、更新、以及清除DNS
此篇文章会带您进行DNS释放.更新以及清除步骤,并协助您就解决您网络方面问题.请在下方选择您所使用的操作系统. Windows 8 在桌面按住Windows + X按键. 选择Command Prom ...
- vu项目中按F5刷新element菜单没有根据路由匹配菜单解决办法
element组件的菜单中设置:default-active,这个是选择哪个菜单的 然后在created里边增加 因为每次刷新都是要经过这个的.注意data里边也要同步.