题目大意:

  给出n个排成一行的城市,每个城市有一个不同的海拔。定义两个城市间的距离等于他们的高度差的绝对值,且绝对值相等的时候海拔低的距离近。有两个人轮流开车,从左往右走。A每次都选最近的,B每次都选次近的。旅行时有一个总路程x,如果两个人的总路程>x 或 有一个人无法按照自己的原则选择目的城市,旅行就终止。

  有两个问:

  1.给出x0,求从哪一个城市出发,使得A走的路程/B走的路程最小。如果B走的路程=0,则比值视为无穷大。如果有多个城市满足要求,则输出海拔最高的那个城市。

  2.给出x和s(出发城市),求旅行终止是A的路程和B的路程。

题解:

【数据范围】
对于30%的数据,有1≤N≤20,1≤M≤20;
对于40%的数据,有1≤N≤100,1≤M≤100;
对于50%的数据,有1≤N≤100,1≤M≤1,000;
对于70%的数据,有1≤N≤1,000,1≤M≤10,000;
对于100%的数据,有1≤N≤100,000,1≤M≤10,000,-1,000,000,000≤Hi≤1,000,000,000,
0≤X0≤1,000,000,000,1≤S
i≤N,0≤Xi≤1,000,000,000,数据保证Hi 互不相同。

先想骗分。。。

  • 50分

对于50%的数据还是很好骗的。每次旅行都直接模拟行走,每次找一个最近或次近,时间O(N*N)。

对于第一问直接枚举起点。时间复杂度为O(N*N*M + N*N*N)

  • 70分

发现50分算法主要是 每次都要找下一个城市 耗费了太多时间,于是干脆直接预处理,O(N*N),总时间O(N*M + N*N)

  • 满分

还是想想改进。。。70分算法的预处理太傻逼了。。其实我们是要每次找到一个海拔与当前城市相差最少的城市。所以算法就有很多种了……比如离散化+链表,双向链表,平衡树(其实用set的话程序比双向链表还好打,因为二分stl都给你弄好了。。)

这里主要介绍下双向链表的做法:就是按高度排序,然后链起来。按城市原始位置从左到右处理接下来的城市是哪个,然后将自己删掉(因为接下来就没用了)。如何找接下来的那个?就是往链表的左右两边找两层,记一个最近和次近。

然后预处理就可以优化到O(N)

then???

发现其实这是一棵树。。。

于是倍增

预处理已经处理出2^0的情况了。接下来直接动规就好了,就可以预处理出每个点的2^i的父亲是谁,以及A走了多少,B走了多少。

then???

现在问题就是给定总路程要怎么求出AB走的路程。

问题可以转化成给定总路程求走了几次。然后就可以用上先前的预处理。假设走了t次,则t肯定可以表示成二进制,而且只有logn位的二进制数。于是可以枚举这一位取0还是1。调用先前处理的数组,看加上所增加的路程后会不会超出x,不会就是1,会就是0。

于是问题就完美解决了!

//代码(巨丑无比)

#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <map>
const int N = 100000 + 9;
struct Link
{
int nxt,pre;
}link[N];
int TOT,n,idx[N];
struct CITY
{
int h,idx;
}city[N];
struct info
{
int u;
long long dis1,dis2;
info(const int a = 0,const long long b = 0,const long long c = 0):u(a),dis1(b),dis2(c){}
}f[20][N][2];
//0: B
//1: A
inline bool cmp(const CITY &lhs,const CITY &rhs){return lhs.h < rhs.h;}
inline int getnext(const int i,const int t){return i?t:(t^1);}
void update(const int i,const int j,const int t)
{
const int nxt = f[i - 1][j][t].u;
const long long dis1 = f[i - 1][j][t].dis1,dis2 = f[i - 1][j][t].dis2;
if (nxt) {
info tmp;
if ((tmp = f[i - 1][nxt][getnext(i - 1,t)]).u)
f[i][j][t] = info(tmp.u,dis1 + tmp.dis1,dis2 + tmp.dis2);
}
}
std::pair<int,int> go(int s,long long x)
{
std::pair<int,int>tmp(0,0);
int turn = 1; // A
for (int i = TOT; i >= 0; --i) {
if (!f[i][s][turn].u) continue;
if (x - f[i][s][turn].dis1 - f[i][s][turn].dis2 < 0) continue;
x -= f[i][s][turn].dis1 + f[i][s][turn].dis2;
tmp.first += f[i][s][turn].dis2;
tmp.second += f[i][s][turn].dis1;
turn = getnext(i,turn);
s = f[i][s][turn].u;
}
return tmp;
}
inline void check(const int id_p,const int id_n,int &Min_h1,int &Min_i1,int &Min_h2,int &Min_i2)
{
if (!id_n) return;
const int dis = std::abs(city[id_p].h - city[id_n].h);
if (dis < Min_h1 || dis == Min_h1 && city[id_n].h < city[Min_i1].h) {
Min_h2 = Min_h1;
Min_i2 = Min_i1;
Min_h1 = dis;
Min_i1 = id_n;
}else if (dis < Min_h2 || dis == Min_h2 && city[id_n].h < city[Min_i2].h) {
Min_h2 = dis;
Min_i2 = id_n;
}
}
inline long long cmp2(const std::pair<int,int>lhs,const std::pair<int,int>rhs)
{
if (!lhs.second && !rhs.second) return 0;
else if (!lhs.second) return 1;
else if (!rhs.second) return -1;
else return 1ll * lhs.first * rhs.second - 1ll * rhs.first * lhs.second;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("drive.in","r",stdin);
freopen("drive.out","w",stdout);
#endif
scanf("%d",&n);
for (int i = 1; i <= n; ++i) {
scanf("%d",&city[i].h);
city[i].idx = i;
}
std::sort(city + 1,city + 1 + n,cmp);
for (int i = 1; i < n; ++i) {
link[i].nxt = i + 1;
link[i + 1].pre = i ;
idx[city[i].idx] = i;
}
idx[city[n].idx] = n;
for (int i = 1; i <= n; ++i) {
int id = idx[i],Min_h1 = 0x7fffffff,Min_i1 = 0,Min_h2 = 0x7fffffff,Min_i2 = 0;
check(id,link[id].pre, Min_h1, Min_i1, Min_h2, Min_i2);
check(id,link[id].nxt, Min_h1, Min_i1, Min_h2, Min_i2);
check(id,link[link[id].pre].pre, Min_h1, Min_i1, Min_h2, Min_i2);
check(id,link[link[id].nxt].nxt, Min_h1, Min_i1, Min_h2, Min_i2);
f[0][i][0] = info(city[Min_i1].idx,Min_h1,0);
f[0][i][1] = info(city[Min_i2].idx,0,Min_h2);
if (link[id].nxt) link[link[id].nxt].pre = link[id].pre;
if (link[id].pre) link[link[id].pre].nxt = link[id].nxt;
}
TOT = static_cast<int>(ceil(log2((double)n)));
for (int i = 1; i <= TOT; ++i)
for (int j = 1; j <= n; ++j) {
update(i,j,0);
update(i,j,1);
}
int x;
scanf("%d",&x);
std::pair<int,int>ans;
int ans_pos = 0;
ans.first = 1; ans.second = 0;
for (int i = 1; i <= n; ++i) {
std::pair<int,int>tmp = go(i,x);
if (cmp2(tmp,ans) < 0) {
ans = tmp;
ans_pos = i;
}else if (cmp2(tmp,ans) == 0 && city[idx[ans_pos]].h < city[idx[i]].h) {
ans = tmp;
ans_pos = i;
}
}
printf("%d\n",ans_pos);
int m;
scanf("%d",&m);
for (int i = 1,x,s; i <= m; ++i) {
scanf("%d%d",&s,&x);
std::pair<int,int> tmp = go(s,x);
printf("%d %d\n",tmp.first,tmp.second);
}
}

  

noip2012开车旅行 题解的更多相关文章

  1. Cogs 1264. [NOIP2012] 开车旅行(70分 暴力)

    1264. [NOIP2012] 开车旅行 ★★☆   输入文件:drive.in   输出文件:drive.out   简单对比时间限制:2 s   内存限制:128 MB [题目描述] 小A 和小 ...

  2. luoguP1081 开车旅行 题解(NOIP2012)

    这道题是真滴火!(一晚上加一节信息课!) 先链接一下题目:luoguP1081 开车旅行 首先,这个预处理就极其变态,要与处理出每一个点往后走A会去哪里,B会去哪里.而且还必须O(nlogn)给它跑出 ...

  3. P1081 [NOIP2012]开车旅行[倍增]

    P1081 开车旅行    题面较为啰嗦.大概概括:一个数列,只能从一个点向后走,两种方案:A.走到和自己差的绝对值次小的点B.走到和自己差的绝对值最小点:花费为此差绝对值:若干询问从规定点向后最多花 ...

  4. NOIP2012开车旅行 【倍增】

    题目 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i 和城 ...

  5. Luogu 1081 [NOIP2012] 开车旅行

    感谢$LOJ$的数据让我调掉此题. 这道题的难点真的是预处理啊…… 首先我们预处理出小$A$和小$B$在每一个城市的时候会走向哪一个城市$ga_i$和$gb_i$,我们有链表和平衡树可以解决这个问题( ...

  6. noip2012 开车旅行

    此题100分的解法就是先预处理出每个点的下一个点之后倍增就好了.其实并没有太大难度. pbihao用双向链表写过了此题.在本地上我treap狂操他,but在rqnoj上,我依靠反复提交才A掉此题(最后 ...

  7. Luogu1081 NOIP2012 开车旅行 倍增

    题目传送门 为什么NOIP的题目都这么长qwq 话说2012的D1T3和D2T3都是大火题啊qwq 预处理神题 对于这种跳跳跳的题目考虑使用倍增优化枚举.先预处理某个点之后距离最小和次小的城市,然后倍 ...

  8. luogu1081 [NOIp2012]开车旅行 (STL::multiset+倍增)

    先用不管什么方法求出来从每个点出发,A走到哪.B走到哪(我写了一个很沙雕的STL) 然后把每个点拆成两个点,分别表示A从这里出发和B从这里出发,然后连边是要A连到B.B连到A.边长就是这次走的路径长度 ...

  9. 洛谷1081 (NOIp2012) 开车旅行——倍增预处理

    题目:https://www.luogu.org/problemnew/show/P1081 预处理从每个点开始a能走多少.b能走多少.可以像dp一样从后往前推. 但有X的限制.所以该数组可以变成倍增 ...

随机推荐

  1. Spring Boot 中使用 MyBatis 整合 Druid 多数据源

    2017 年 10 月 20 日   Spring Boot 中使用 MyBatis 整合 Druid 多数据源 本文将讲述 spring boot + mybatis + druid 多数据源配置方 ...

  2. Can you answer these queries?(HDU4027+势能线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4027 题目: 题意:n个数,每次区间更新将其数值变成它的根号倍(向下取整),区间查询数值和. 思路:易 ...

  3. Chrome 浏览器 autocomplete off无效

    在表单填写时突然发现autocomplete 失效了 网上搜索后得出大概意思是在某些情况下确实无效[捂脸] 解决方案 大致原因是浏览器默认为type为password的input标签自动填充密码 这样 ...

  4. 转 一次完整地http请求

    作者:斯巴达克斯 时间:January 11, 2014 分类:WEB 声明:本文章中的说法仅是个人理解总结,不一定完全正确,但是可以有助于理解. 关于HTTP协议可以参考以下: HTTP协议漫谈 h ...

  5. 【1】记一次破解wifi

    当然,使用的依旧是aircrack套件,这次依旧是跑字典,今天,捉到了另一个实验室icephone的wpa握手包,我猜测实验室的wifi一般都跟自己的名字有关,icephone刚好是8位字母,于是我就 ...

  6. php中的__call()函数重载

    <?php #调用类中没有的方法时, 会自动调用__call方法重载 #第一个参数是调用时的方法名, 第二个参数为参数组成的数组 class Cat{ public function Hello ...

  7. leetcode 141 142. Linked List Cycle

    题目描述: 不用辅助空间判断,链表中是否有环 /** * Definition for singly-linked list. * struct ListNode { * int val; * Lis ...

  8. 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记8——载入三维模型&Alpha混合技术&深度测试与Z缓存

    第17章 三维游戏模型的载入 主要是如何从3ds max中导出.X文件,以及如何从X文件加载三维模型到DirextX游戏程序里.因为复杂的3D物体,要用代码去实现,那太反人类了,所以我们需要一些建模软 ...

  9. 机器学习方法(四):决策树Decision Tree原理与实现技巧

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入. 前面三篇写了线性回归,lass ...

  10. hdu 1114(完全背包)

    Piggy-Bank Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...