【NOIP2012提高组】开车旅行
题目
到处都有
闲话
碰巧考场上出了 \(Noip\) 原题
然后这题自然而然想到
预处理一个点开始分别由 \(A,B\) 驾驶会走到的下一个点
然后用预处理的数组求答案
当然你会发现 \(X=X0\) 这一问和后面的问的解法没什么区别
这都不是重点
\(ccf\) 很良心给暴力 \(70\) 分
然后 \(100\) 分码得非常开心
解法一
没错,就是按闲话的思路
求下一个点 \(O(n^2)\) 可以做到,往后扫一遍依题算即可
然后对于每个询问暴力一步一步走知道无路可走
竟然给 \(70\) !
\(Code\)
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int N = 1e5 + 5;
int n, m, h[N], nxt[N][2];
struct node{int a, b;};
void getNext()
{
h[0] = 0x3f3f3f3f;
for(register int i = 1; i <= n; i++)
{
int k1 = 0, k2 = 0;
for(register int j = i + 1; j <= n; j++)
{
int z = abs(h[i] - h[j]);
if (z < abs(h[i] - h[k1]) || (z == abs(h[i] - h[k1]) && h[j] < h[k1])) k2 = k1, k1 = j;
else if (z == abs(h[i] - h[k1]) || z < abs(h[i] - h[k2]) || (z == abs(h[i] - h[k2]) && h[j] < h[k2])) k2 = j;
}
nxt[i][1] = k1, nxt[i][0] = k2;
}
}
inline node solve(int S, int X)
{
int p = 0, x = 0;
node ret = {0, 0};
while (nxt[S][p] != 0 && x + abs(h[S] - h[nxt[S][p]]) <= X)
{
if (!p) ret.a += abs(h[S] - h[nxt[S][p]]);
else ret.b += abs(h[S] - h[nxt[S][p]]);
x += abs(h[S] - h[nxt[S][p]]), S = nxt[S][p], p ^= 1;
}
return ret;
}
inline double calc(int x, int y)
{
if (!y) return 0x3f3f3f3f;
return 1.0 * x / y;
}
int main()
{
scanf("%d", &n);
for(register int i = 1; i <= n; i++) scanf("%d", &h[i]);
getNext();
LL S, X;
scanf("%d", &X);
int k = 0; double ans = 0x3f3f3f3f;
for(register int i = 1; i <= n; i++)
{
node t = solve(i, X);
if (calc(t.a, t.b) < ans || (calc(t.a, t.b) == ans && h[i] > h[k]))
ans = calc(t.a, t.b), k = i;
}
printf("%d\n", k);
scanf("%d", &m);
for(; m; m--)
{
scanf("%lld%lld", &S, &X);
node t = solve(S, X);
printf("%d %d\n", t.a, t.b);
}
}
解法二
没错,就是按照解法一的思路
首先我们发现一步一步跳太低效
也太给人灵感
一步一步跳?好熟悉?!
那就倍增啊
\(2\) 的幂次跳就是快!!
然后这不是最关键的地方
因为预处理还卡在 \(O(n^2)\)
相当于什么都没干
所以我们总得干点什么
是的
预处理实际上非常好玩
你可以用排序+链表非常常规地搞出来
当然,你可以更常规用平衡树来搞搞
我选择了后者(当然不可能手打平衡树,\(set\) 就是好)
这东西比较繁琐,要慢慢讨论
收获
用 \(set\) 如果涉及多个关键字怎么办?
这样定义
#include<set>
using namespace std;
struct nod{int h, id;};
struct cmp{bool operator()(const nod &a, const nod &b){return a.h < b.h;}};
set<nod, cmp> s;
于是我们申明了一个节点为 \(nod\) 类型的平衡树
那么各类使用参数也相应的改变
你会发现 \(h\) 是第一关键字
那它在比较时会先比较第一关键字,再比较第二关键字
学会了!
哦,\(AC\) 代码记录一波
#include<cstdio>
#include<algorithm>
#include<set>
#define LL long long
using namespace std;
const int N = 1e5 + 5;
int n, m, h[N], nxt[N][2];
LL F[N][20], A[N][20], B[N][20];
struct node{LL a, b;};
struct nod{int h, id;};
struct cmp{bool operator()(const nod &a, const nod &b){return a.h < b.h;}};
set<nod, cmp> tr;
set<nod, cmp>::iterator it, itt;
inline void swap(nod &x, nod &y){nod t; t = x, x = y, y = t;}
void getNext()
{
tr.insert(nod{h[n], n});
for(register int i = n - 1; i; i--)
{
nod k1 = {0x3f3f3f3f, 0}, k2 = {0x3f3f3f3f, 0};
it = tr.lower_bound(nod{h[i], i});
if (it == tr.begin())
{
k1 = *it;
if (++it != tr.end()) k2 = *it;
}
else if (it == tr.end())
{
k1 = *(--it);
if (it != tr.begin()) k2 = *(--it);
}
else{
itt = it, --it;
int count = 0; nod l = *it, r = *itt;
while (1)
{
if (abs(h[i] - l.h) < abs(h[i] - r.h) || (abs(h[i] - l.h) == abs(h[i] - r.h) && l.h < r.h))
{
if (!count)
{
k1 = l, ++count;
if (it == tr.begin()){l = {0x3f3f3f3f, 0}; continue;}
l = *(--it);
}
else{k2 = l; break;}
}
else{
if (!count)
{
k1 = r, ++count, r = *(++itt);
if (itt == tr.end()) r = {0x3f3f3f3f, 0};
}
else{k2 = r; break;}
}
}
}
if (abs(h[i] - k1.h) > abs(h[i] - k2.h) || (abs(h[i] - k1.h) == abs(h[i] - k2.h) && k1.h > k2.h)) swap(k1, k2);
nxt[i][1] = k1.id, nxt[i][0] = k2.id;
tr.insert(nod{h[i], i});
}
}
void getF()
{
for(register int i = 1; i <= n; i++)
F[i][0] = nxt[nxt[i][0]][1],
A[i][0] = abs(h[i] - h[nxt[i][0]]),
B[i][0] = abs(h[nxt[i][0]] - h[nxt[nxt[i][0]][1]]);
for(register int j = 1; j <= 17; j++)
for(register int i = 1; i <= n; i++)
F[i][j] = F[F[i][j - 1]][j - 1],
A[i][j] = A[i][j - 1] + A[F[i][j - 1]][j - 1],
B[i][j] = B[i][j - 1] + B[F[i][j - 1]][j - 1];
}
inline node solve(int S, LL X)
{
int p = 0; LL x = 0;
node ret = {0, 0};
for(register int i = 17; i >= 0; i--)
if (F[S][i] && x + A[S][i] + B[S][i] <= X)
{
ret.a += A[S][i], ret.b += B[S][i];
x += A[S][i] + B[S][i], S = F[S][i];
}
while (nxt[S][p] && x + abs(h[S] - h[nxt[S][p]]) <= X)
{
if (!p) ret.a += abs(h[S] - h[nxt[S][p]]);
else ret.b += abs(h[S] - h[nxt[S][p]]);
x += abs(h[S] - h[nxt[S][p]]), S = nxt[S][p], p ^= 1;
}
return ret;
}
inline double calc(int x, int y)
{
if (!y) return 0x3f3f3f3f;
return 1.0 * x / y;
}
int main()
{
scanf("%d", &n);
for(register int i = 1; i <= n; i++) scanf("%d", &h[i]);
getNext(), getF();
int S; LL X;
scanf("%lld", &X);
int k = 0; double ans = 0x3f3f3f3f;
for(register int i = 1; i <= n; i++)
{
node t = solve(i, X);
if (calc(t.a, t.b) < ans || (calc(t.a, t.b) == ans && h[i] > h[k]))
ans = calc(t.a, t.b), k = i;
}
printf("%d\n", k);
scanf("%d", &m);
for(; m; m--)
{
scanf("%d%lld", &S, &X);
node t = solve(S, X);
printf("%lld %lld\n", t.a, t.b);
}
}
【NOIP2012提高组】开车旅行的更多相关文章
- [NOIP2012提高组]开车旅行
题目:洛谷P1081.Vijos P1780.codevs1199. 题目大意:有n座海拔高度不相同的城市(编号1~n),两城市的距离就是两城市海拔之差.规定每次只能从编号小的城市走到编号大的城市. ...
- 刷题总结——疫情控制(NOIP2012提高组)
题目: 题目背景 NOIP2012 提高组 DAY2 试题. 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都 ...
- GZOJ 1361. 国王游戏【NOIP2012提高组DAY1】
国王游戏[NOIP2012提高组DAY1] Time Limit:1000MS Memory Limit:128000K Description 国王游戏(game.cpp/c/pas) [问题描述] ...
- 【NOIP2015模拟11.5】JZOJ8月5日提高组T3 旅行
[NOIP2015模拟11.5]JZOJ8月5日提高组T3 旅行 题目 若不存在第\(k\)短路径时,输出"Stupid Mike" 题解 题意 给出一个有\(n\)个点的树 问这 ...
- [NOIP2012] 提高组 洛谷P1081 开车旅行
题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...
- NOIP2012 提高组 Day 1
期望得分:100+100+70=270 实际得分:100+50+70=220 T2 没有底 最后剩余时间来不及打高精.思路出现错误 T1 Vigenère 密码 题目描述 16 世纪法国外交家 Bla ...
- [NOIP2012] 提高组 洛谷P1084 疫情控制
题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...
- [NOIP2012] 提高组 洛谷P1080 国王游戏
题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍 ...
- [NOIP2012] 提高组 洛谷P1083 借教室
题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自然 ...
- [NOIP2012] 提高组 洛谷P1082 同余方程
题目描述 求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. 输入输出格式 输入格式: 输入只有一行,包含两个正整数 a, b,用一个空格隔开. 输出格式: 输出只有一行,包含一个正 ...
随机推荐
- 记录一次从linux移动一个项目到windows遇到的问题
前言 这几天在linux平台写了一个垃圾软件,浪费了我10多天的时间,感觉很垃圾,然后我想在windows平台打包这个软件,然后出现了一个项目中有相同文件名的问题,导致一些文件相互覆盖 问题描述 我把 ...
- 关于linux mint新增加的鼠标样式的示例图片不能正确显示的解决办法
前言 我相信你在linux mint 做鼠标主题美化的时候一定遇到过这样的问题 没错!!! 下载的鼠标的主题的示例图片不能正确显示,当然这样虽然不影响正常的鼠标主题更换使用,但是对于我这种强迫症来说简 ...
- HSSFSheet XSSFWorkbook SXSSF Java读取Excel数据
HSSF是POI工程对Excel 97(-2007)文件操作的纯Java实现 XSSF是POI工程对Excel 2007 OOXML (.xlsx)文件操作的纯Java实现 SXSSF通过一个滑动窗口 ...
- 【每日一题】【双指针/栈/reverse】2022年2月19日-判断是否为回文字符串
给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文.如果是回文请返回true,否则返回false. 字符串回文指该字符串正序与其逆序逐字符一致. 数据范围:0 < n \l ...
- 痞子衡嵌入式:我被邀请做贸泽电子&与非网联合推出的《对话工程师》节目嘉宾
<对话工程师>是「贸泽电子」赞助.「与非网」制作的一档网络节目,自2022年11月起,邀请不同技术领域的资深工程师,聊聊开发过程中的经验感悟,栏目共 10 期,痞子衡有幸被邀请做了第 4 ...
- 小程序与app区别及测试点
小程序和app区别 1. 用户获取渠道区别 小程序: 二维码.用户分享推荐.搜索小程序 APP: 需要去应用市场(或其他)下载 2. 下载.安装卸载 小程序: 不需下载安装,清除时直接删除小程序 AP ...
- prometheus-监控docker服务器
1. prometheus-监控docker服务器 prometheus-监控docker服务器 cAdvisor(Container Advisor):用于收集正在运行的容器资源使用和性能信息. 项 ...
- [python] 基于matplotlib实现树形图的绘制
树形图Tree diagram (代码下载) 本文旨在描述如何使用Python实现基本的树形图.要实现这样的树形图,首先需要有一个数值矩阵.每一行代表一个实体(这里是一辆汽车).每列都是描述汽车的变量 ...
- 初学《python编程从入门到实践》web应用程序,出现错误
一开始是遇到了TemplateDoesNotExist的错误,上百度都是说改settings.py里面的TEMPLATE的DIRS, 但我改了还是出现问题, 我用的<python编程从入门到实践 ...
- 看我是如何用C#编写一个小于8KB的贪吃蛇游戏的
译者注:这是Michal Strehovský大佬的一篇文章,他目前在微软.NET Runtime团队工作,主要是负责.NET NativeAOT功能的开发.我在前几天看到这篇文章,非常喜欢,虽然它的 ...