感谢$LOJ$的数据让我调掉此题。

这道题的难点真的是预处理啊……

首先我们预处理出小$A$和小$B$在每一个城市的时候会走向哪一个城市$ga_i$和$gb_i$,我们有链表和平衡树可以解决这个问题(当然是$set$啦)。

我们设$f_{i, j, k}$表示当前轮到$k$开车($0$为小$A$,$1$为小$B$),从城市$j$出发走$2^i$天能走到的城市,$da_{i, j, k}$和$db_{i, j, k}$分表示$k$先开车,从城市$j$出发走$2^i$天小$A$和小$B$分别行驶的路程。

然后转移就很显然了,唯一要注意的是当$i == 1$的时候$2^{i - 1}$是一个奇数,开车的人要调换一下。

对于每一个询问给定了$s$和$X$,我们只要倒序循环二进制拼凑一下行驶的里程数看看是否会超过$X$就可以计算出小$A$和小$B$分别行驶的里程数了。

第一问可以每一个城市都代进去算一下。

时间复杂度$O((n + m)logn)$。

Code:

#include <cstdio>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair <ll, int> pin; const int N = 1e5 + ;
const int Lg = ;
const ll inf = 1LL << ;
const double eps = 1e-; int n, qn, ga[N], gb[N], f[Lg][N][];
ll a[N], la, lb, da[Lg][N][], db[Lg][N][];
set <pin> s; template <typename T>
inline T abs(T x) {
return x > ? x : -x;
} template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void solve(int st, ll dis) {
int p = st;
for(int i = ; i >= ; i--) {
if(f[i][p][] != n + && la + lb + da[i][p][] + db[i][p][] <= dis) {
la += da[i][p][], lb += db[i][p][];
p = f[i][p][];
}
}
} int main() {
// freopen("drive5.in", "r", stdin); read(n);
for(int i = ; i <= n; i++) {
read(a[i]);
s.insert(pin(a[i], i));
}
a[n + ] = inf; for(int i = ; i <= n; i++) {
#define h first
#define id second set <pin> :: iterator it = s.find(pin(a[i], i)), itp, itn;
pin nxt = pin(inf, n + ), pre = pin(-inf, n + ); itp = itn = it; ++itn;
if(itn != s.end()) nxt = *itn;
if(itp != s.begin()) {
--itp;
pre = *itp;
} if(a[i] - pre.h <= nxt.h - a[i]) {
gb[i] = pre.id;
if(itp != s.begin()) {
--itp;
pre = *itp;
} else pre = pin(-inf, n + );
} else {
gb[i] = nxt.id;
if(itn != s.end()) ++itn;
if(itn != s.end()) nxt = *itn;
else nxt = pin(inf, n + );
} if(a[i] - pre.h <= nxt.h - a[i]) ga[i] = pre.id;
else ga[i] = nxt.id; s.erase(it); #undef h
#undef id
} /* for(int i = 1; i <= n; i++)
printf("%d ", ga[i]);
printf("\n");
for(int i = 1; i <= n; i++)
printf("%d ", gb[i]);
printf("\n"); */ for(int i = ; i <= n; i++)
f[][i][] = ga[i], f[][i][] = gb[i];
for(int i = ; i <= ; i++)
for(int j = ; j <= n; j++)
for(int k = ; k <= ; k++) {
if(i == )
f[i][j][k] = f[i - ][f[i - ][j][k]][ - k];
else
f[i][j][k] = f[i - ][f[i - ][j][k]][k];
} for(int i = ; i <= n; i++) {
da[][i][] = 1LL * abs(a[i] - a[ga[i]]);
da[][i][] = 0LL;
db[][i][] = 0LL;
db[][i][] = 1LL * abs(a[i] - a[gb[i]]);
} for(int i = ; i <= ; i++) {
for(int j = ; j <= n; j++)
for(int k = ; k <= ; k++) {
if(i == ) {
da[][j][k] = da[][j][k] + da[][f[][j][k]][ - k];
db[][j][k] = db[][j][k] + db[][f[][j][k]][ - k];
} else {
da[i][j][k] = da[i - ][j][k] + da[i - ][f[i - ][j][k]][k];
db[i][j][k] = db[i - ][j][k] + db[i - ][f[i - ][j][k]][k];
}
}
} // printf("%lld %lld\n", da[18][1][0], db[18][1][0]); ll x0; read(x0);
int res = ; double nowVal, resVal = 1.0 * inf;
for(int i = ; i <= n; i++) {
la = lb = 0LL;
solve(i, x0); if(lb == 0LL) nowVal = 1.0 * inf;
else nowVal = 1.0 * la / lb;
if(nowVal < resVal && abs(nowVal - resVal) > eps)
res = i, resVal = nowVal;
else if(abs(nowVal - resVal) < eps) {
if(a[res] < a[i]) res = i;
}
} printf("%d\n", res);
for(read(qn); qn--; ) {
int st; ll dis;
read(st), read(dis); la = lb = 0LL;
solve(st, dis); printf("%lld %lld\n", la, lb);
} return ;
}

Luogu 1081 [NOIP2012] 开车旅行的更多相关文章

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

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

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

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

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

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

  4. noip2012开车旅行 题解

    题目大意: 给出n个排成一行的城市,每个城市有一个不同的海拔.定义两个城市间的距离等于他们的高度差的绝对值,且绝对值相等的时候海拔低的距离近.有两个人轮流开车,从左往右走.A每次都选最近的,B每次都选 ...

  5. NOIP2012开车旅行 【倍增】

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

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

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

  7. noip2012 开车旅行

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

  8. Luogu1081 NOIP2012 开车旅行 倍增

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

  9. Luogu 1081 【NOIP2012】开车旅行 (链表,倍增)

    Luogu 1081 [NOIP2012]开车旅行 (链表,倍增) Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已 ...

随机推荐

  1. Alex and broken contest CodeForces - 877A

    /* Name: Copyright: Author: Date: 2018/5/2 10:45:16 Description: 要求出现一个朋友的名字,仅一次 */ #include <ios ...

  2. skynet源码阅读<5>--协程调度模型

    注:为方便理解,本文贴出的代码部分经过了缩减或展开,与实际skynet代码可能会有所出入.    作为一个skynet actor,在启动脚本被加载的过程中,总是要调用skynet.start和sky ...

  3. nodejs express mysql

  4. SQL Server 学习系列之六

    SQL Server 学习系列之六 SQL Server 学习系列之一(薪酬方案+基础) SQL Server 学习系列之二(日期格式问题) SQL Server 学习系列之三(SQL 关键字) SQ ...

  5. BZOJ4198:[NOI2015]荷马史诗

    浅谈\(Huffman\)树:https://www.cnblogs.com/AKMer/p/10300870.html 题目传送门:https://lydsy.com/JudgeOnline/pro ...

  6. bzoj 3505 [Cqoi2014]数三角形——排列组合

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3505 好题!一定要经常回顾! 那个 一条斜线上的点的个数是其两端点横坐标之差和纵坐标之差的g ...

  7. VirtualBox为虚拟OS硬盘扩容

    1.关闭虚拟OS. 2.进入到在VirtualBox的安装路径,执行命令例子如: VBoxManage.exe modifyhd F:\VM\Debian7.2.vdi --resize 40000 ...

  8. 用Azure上Cognitive Service的Face API识别人脸

    Azure在China已经发布了Cognitive Service,包括人脸识别.计算机视觉识别和情绪识别等服务. 本文将介绍如何用Face API识别本地或URL的人脸. 一 创建Cognitive ...

  9. 机器学习:集成学习(集成学习思想、scikit-learn 中的集成分类器)

    一.集成学习的思想 集成学习的思路:一个问题(如分类问题),让多种算法参与预测(如下图中的算法都可以解决分类问题),在多个预测结果中,选择出现最多的预测类别做为该样本的最终预测类别: 生活中的集成思维 ...

  10. Redis事务和watch

    redis的事务 严格意义来讲,redis的事务和我们理解的传统数据库(如mysql)的事务是不一样的. redis中的事务定义 Redis中的事务(transaction)是一组命令的集合. 事务同 ...