感谢$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. New Concept English three (47)

    Pollution is the price we pay for an overpopulated, over industrialized planet. When you come to thi ...

  2. 搞定thrift双向消息

    thrift作为脱胎于facebook的rpc框架,各方面都非常优秀.清晰的分层设计,多语言的支持,以及不输protocolbuffer的效率(compact下优于protocolbuffer),都让 ...

  3. matrix-gui-2.0 将javascript文件夹改成js文件夹

    /******************************************************************************** * matrix-gui-2.0 将 ...

  4. UOJ#454. 【UER #8】打雪仗

    UOJ#454. [UER #8]打雪仗 http://uoj.ac/problem/454 分析: 好玩的通信题~ 把序列分成三块,\(bob\)先发出这三块中询问点最多的一块给\(alice\). ...

  5. LeetCode Continuous Subarray Sum

    原题链接在这里:https://leetcode.com/problems/continuous-subarray-sum/description/ 题目: Given a list of non-n ...

  6. 四、python沉淀之路--元组

    一.元组基本属性 1.元组不能被修改,不能被增加.不能被删除 2.两个属性 tu.count(22)       #获取指定元素在元组中出现的次数tu.index(22)      #获取指定元素的缩 ...

  7. 开启MySQL的sql语句记录

    在开发的时候经常会想看一下MySQL最终执行的sql或者想保存sql记录,所以我们可以启用MySQL的sql记录功能. 开启方法:Linux下编辑MySQL的my.cnf文件,windows下编辑my ...

  8. Asp.NET Core+ABP框架+IdentityServer4+MySQL+Ext JS之验证码

    验证码这东西,有人喜欢有人不喜欢.对于WebApi是否需要验证码,没去研究过,只是原来的SimpleCMS有,就加上吧. 在WeiApi上使用验证码,关键的地方在于WeiApi是没有状态的,也就是说, ...

  9. java代码随机数组合,随机号码产生器

    总结:还是掌握方法的运用++++++ package com.c2; //随机数组合,随机号码产生器 //随机号码 import java.util.Random; public class rfe ...

  10. spring容器启动的三种方式

    一.在Web项目中,启动Spring容器的方式有三种,ContextLoaderListener.ContextLoadServlet.ContextLoaderPlugin. 1.1.监听器方式: ...