开车旅行(NOIP2012提高组)

2023-10-15 13:50
文章标签 提高 旅行 noip2012 开车

本文主要是介绍开车旅行(NOIP2012提高组),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接
这道题最基本的思路是用倍增,但是其实它的难点在预处理部分。
倍增的部分此次就不细说了,和之前的最近公共祖先的思想类似。
我们主要来探讨一下预处理的部分。
我们需要预处理出每个城市小A和小B的选择目标和对应的距离,接下来就可以处理出进行2k轮开车的目的地和距离了。所以前者才是重中之重,而前者如果要用暴力的方法会tle的。
有人可能会疑惑,我们找当前点的后面两三个不就可以了?为什么会tle呢?
实际上并不是序号相差很远距离就很远,实际上有可能第一个城市和最后一个城市最近,可以举个例子,城市海拔如下:
1 3 4 5 6 7 8 9 10 11 2
也许你也会有疑问,不是说右边的城市在左边城市的东边吗?这可能吗?
注意这题并不是线性的,而是2D的。所以可以画出如下的图:
在这里插入图片描述

所以,这么看来,暴力算法的复杂度就是n方,就会超时。
所以我们需要换种方法。
我们不妨换种顺序,因为是用海拔来决定高度,所以海拔相距最近的,一定是距离最近的。
所以我们可以按照海拔进行排序,排好序后就按照这个顺序建立双向链表。
这时我们就知道了,对于某一城市,小a和小b要么没有选择,要么选择的城市一定在当前城市链表中的前两个和两个中。
为什么不是前一个和后一个?因为如果一个点在链表边上,它就只有一侧,所以把特殊情况考虑在内,就是前两个和后两个。
那么你可能又会觉得奇怪,万一这几个当中有城市在当前城市的西边怎么办?这样这个范围就可能不够了?
所以我们的处理顺序就成了很大的很关键,我们按照城市编号顺序去处理每个城市的目标,处理完后就把当前城市删除(这也是用双向链表的原因),这样每次处理就可以保证当前链表中的其他城市均在当前城市的东边,而保证我们所取的范围是够的。
当然你也许还会有疑问,那我怎么定位要处理的城市在链表中的位置呢?
这个准备的指针数组就好了。
这样就可以把预处理的复杂度从O(n2)降低到O(n),这样就可以过了
下面是参考代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAX 2000000000
using namespace std;
const int maxn=100005;
struct City{int num;int h;City *last,*next; 
}city[maxn]; 
City *pos[maxn];
long long n,m,x0,ss[maxn],xx[maxn],h[maxn],maxk; 
long long aaim[maxn],baim[maxn],adis[maxn],bdis[maxn];
long long longdis[maxn][20],longaim[maxn][20];
long long alongdis[maxn][20],alongaim[maxn][20];
long long s0,da=-1,db=-1;
void fun1(long long curs){long long tot=0,cura=0,curb=0,curn=curs;for(int k=maxk;k>=0;k--){if(longaim[curn][k]!=0&&longdis[curn][k]+tot>x0){continue;}if(longaim[curn][k]==0){continue;}tot+=longdis[curn][k];cura+=alongdis[curn][k];curn=longaim[curn][k];}curb=tot-cura;if(aaim[curn]!=0&&tot+adis[curn]<=x0){tot+=adis[curn];cura+=adis[curn];}if(da==-1){s0=curs;da=cura;db=curb;}else if(db==0&&curb==0&&h[curs]>h[s0]){s0=curs;da=cura;db=curb;}else if(db==0){s0=curs;da=cura;db=curb;}else if(curb==0){}else if(da*curb>db*cura){s0=curs;da=cura;db=curb;}else if(da*curb==db*cura&&h[curs]>h[s0]){s0=curs;da=cura;db=curb;} 
}
void fun2(long long s,long long xi){long long tot=0,cura=0,curb=0,curn=s;for(int k=maxk;k>=0;k--){if(longaim[curn][k]!=0&&longdis[curn][k]+tot>xi){continue;}if(longaim[curn][k]==0){continue;}tot+=longdis[curn][k];cura+=alongdis[curn][k];curn=longaim[curn][k];}curb=tot-cura;if(aaim[curn]!=0&&tot+adis[curn]<=xi){tot+=adis[curn];cura+=adis[curn];}printf("%d %d\n",cura,curb); 
}
int cmp(City a,City b){return a.h<b.h;
}
void update(City cur,City aim){if((abs(cur.h-aim.h)<bdis[cur.num])||(abs(cur.h-aim.h)==bdis[cur.num]&&aim.h<pos[baim[cur.num]]->h)){adis[cur.num]=bdis[cur.num];aaim[cur.num]=baim[cur.num];bdis[cur.num]=abs(cur.h-aim.h);baim[cur.num]=aim.num;}else if((abs(cur.h-aim.h)<adis[cur.num])||(abs(cur.h-aim.h)==adis[cur.num]&&aim.h<pos[aaim[cur.num]]->h)){adis[cur.num]=abs(cur.h-aim.h);aaim[cur.num]=aim.num;}
}
int main(){scanf("%lld",&n);for(int i=1;i<=n;i++){scanf("%lld",&city[i].h);adis[i]=bdis[i]=MAX;city[i].num=i;}scanf("%lld%lld",&x0,&m);for(int i=0;i<m;i++){scanf("%lld%lld",&ss[i],&xx[i]);}sort(city+1,city+n+1,cmp);for(int i=1;i<=n;i++){if(i==1){city[i].last=NULL;}else{city[i].last=&city[i-1];}if(i==n){city[i].next=NULL;}else{city[i].next=&city[i+1];}pos[city[i].num]=&city[i];}for(int i=1;i<=n;i++){City *p;p=pos[i]->last;if(p!=NULL){update(*pos[i],*p);p=p->last;if(p!=NULL){update(*pos[i],*p);}}p=pos[i]->next;if(p!=NULL){update(*pos[i],*p);p=p->next;if(p!=NULL){update(*pos[i],*p);}}if(pos[i]->next!=NULL){pos[i]->next->last=pos[i]->last;}if(pos[i]->last!=NULL){pos[i]->last->next=pos[i]->next;}} for(int i=1;i<=n;i++){if(aaim[i]!=0&&baim[aaim[i]]!=0){longdis[i][0]=adis[i]+bdis[aaim[i]];longaim[i][0]=baim[aaim[i]];alongdis[i][0]=adis[i];alongaim[i][0]=baim[aaim[i]];}else{longaim[i][0]=0;longdis[i][0]=MAX;alongdis[i][0]=MAX;alongaim[i][0]=0;}}for(int k=1;(1<<k)<=n;k++){for(int i=1;i<=n;i++){if(longaim[i][k-1]!=0&&longaim[longaim[i][k-1]][k-1]!=0){longdis[i][k]=longdis[i][k-1]+longdis[longaim[i][k-1]][k-1];longaim[i][k]=longaim[longaim[i][k-1]][k-1];}else{longdis[i][k]=MAX;longaim[i][k]=0;}if(alongaim[i][k-1]!=0&&alongaim[alongaim[i][k-1]][k-1]!=0){alongdis[i][k]=alongdis[i][k-1]+alongdis[alongaim[i][k-1]][k-1];alongaim[i][k]=alongaim[alongaim[i][k-1]][k-1];}else{alongdis[i][k]=MAX;alongaim[i][k]=0;}}maxk=k;}	for(int i=1;i<=n;i++){fun1(i);}printf("%d\n",s0);for(int i=0;i<m;i++){fun2(ss[i],xx[i]);}return 0;
} 

这篇关于开车旅行(NOIP2012提高组)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/218136

相关文章

键盘快捷键:提高工作效率与电脑操作的利器

键盘快捷键:提高工作效率与电脑操作的利器 在数字化时代,键盘快捷键成为了提高工作效率和优化电脑操作的重要工具。无论是日常办公、图像编辑、编程开发,还是游戏娱乐,掌握键盘快捷键都能带来极大的便利。本文将详细介绍键盘快捷键的概念、重要性、以及在不同应用场景中的具体应用。 什么是键盘快捷键? 键盘快捷键,也称为热键或快捷键,是指通过按下键盘上的一组键来完成特定命令或操作的方式。这些快捷键通常涉及同

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

如何提高 GitHub 的下载速度

如何提高 GitHub 的下载速度 文章目录 如何提高 GitHub 的下载速度1. 注册账号2. 准备好链接3. 创建仓库4. 在码云上下载代码5. 仓库更新了怎么办 一般来说,国内的朋友从 GitHub 上面下载代码,速度最大是 20KB/s,这种龟速,谁能忍受呢? 本文介绍一种方法——利用“码云”,可以大大提高下载速度,亲测有效。 1. 注册账号 去“码云”注册一

如何提高开发的效率,让老板不知所措的给你发工资

设计模式 UML JSP 编程 数据结构 1.你可能会常常发现,写了一段代码后,编译程序时是一大堆的出错 (原因:语法不熟)  ──别担心,这是每个程序员必须经历的事,这时候你就需要更大的耐心及细心,对每一行代码进行仔细人阅读并改正,这个很重要,这可以培养你的理解代码能力,所以要常读程序,不要等到程序运行以后才知道你的程序的结果。  ──如何避免:在写代码以前,要认真的学习计算机语

Java开发实例大全提高篇——Applet的应用

开发十年,就只剩下这套架构体系了! >>>    第21章  Applet的应用 21.1  Applet在html中的使用 实例549  在html中显示Applet HtmlShowApplet.java     public void paint(Graphics g){         g.drawString("html文件已经运行", 50, 50);// 绘制文本

Java开发实例大全提高篇——Java安全

开发十年,就只剩下这套架构体系了! >>>    第6篇  Java安全与Applet应用篇 第20章  Java安全 20.1  Java对称加密 实例531  使用BASE64加密     public static String encryptBASE64(byte[] data) {         //加密数据         return (new BASE64Encoder()

2024国赛论文拿奖快对照这几点及评阅要点,勿踩雷区!(国赛最后冲刺,提高获奖概率)

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 2024“高教社杯”全国大学生数学建模竞赛已过去第三个夜晚,小伙伴们都累了没有,如果感到思维滞涩,别忘了稍作休息,放松一下自己,准备迎接国赛非常重要的收尾阶段——论文。 国赛这几天的努力最后都

C++提高编程三(vector容器、deque容器)

文章目录 vector容器vector赋值操作vector容量和大小vector插入和删除vector数据存取vector互换容器vector预留空间deque容器构造函数deque赋值操作deque大小操作deque 插入和删除deque 数据存取deque 排序 vector容器 vector容器数据结构和数组相似,也称为单端数组。区别在于数组是静态空间,vector可以

随着人们网络安全意识提高,软件架构设计与评估也成为重中之重

目录 案例 【题目】 【问题 1】(13 分) 【问题 2】(12分) 【答案】 【问题 1】答案 【问题 2】答案 相关推荐 案例         阅读以下关于软件架构设计与评估的叙述,回答问题 1 和问题 2。 【题目】         某电子商务公司为正更好地管理用户,提升企业销售业绩,拟开发一套用户管理系统。该系统的基本功能是根据用户的消费级别、消费历史、信

兔子-提高xampp中php的版本/提高php项目的版本

我是一个php菜鸟,我的博客也不是多么高大上,我只是记录下我自学过程中遇到的问题,有待于以后在复习,同时也希望能帮助到大家。 我用的开发环境是:xampp+phpstorm 解决办法:安装一个带有高版本php的xampp 以下是我出现这个问题到解决问题的过程。 曾经我在这里改php的版本,但是echo phpversion();版本总是不变。 后来经过问别人,别人建议我