【题目链接】

【题目大意】

从西到东的坐标轴\([1,n]\)上有\(n\)个海拔互不相同的城市,每两个城市之间的距离定义为\(dis(i,j)=|h_i-h_j|\)

小\(A\)和小\(B\)轮着开车,小\(A\)先开始开车。两个人的车一直向东行驶,并且最多行驶\(X\)公里。

小\(A\)和小\(B\)开车的习惯不一样。如果开车从西到东,小\(A\)每一次都会找到后面海拔和当前城市相差次小的城市,小\(B\)则会选择最小值

如果多个满足条件的城市,那么选择海拔较低的。

现在请回答两个问题:

  • 如果给定\(X=X_0\),问从哪一个城市开始行驶,可以让小\(A\)开的距离和小\(B\)开的距离比值最小。
  • 每一次询问给定起点\(S_i\)和\(X_i\),问从城市\(S_i\)开始行驶,最多行驶\(X_i\)可以行驶到哪一个城市。

【思路要点】

  • 首先预处理出每一个城市,如果当前是小\(A\)或者小\(B\)开车,后要到达的城市,用\(set\)维护一下就可以了。
  • 我们可以发现这个过程可以用模拟来进行,但是可以发现这个问题如果固定了起点,那么就满足倍增的优化思路了。
  • \(g[u][i][0..1]\)表示起点是\(u\),向后开了\(2^i\)天,一开始是\([0..1]\)开的车,\(0\)是小\(A\),\(1\)是小\(B\)。
  • 因为需要知道距离,那么就预处理一下距离,\(da[u][i][0..1],db[u][i][0..1]\)将上式的起点改为小\(A\)和小\(B\)开车的距离。
  • 注意\(2\)拆分后得到的是\(1+1\),奇偶性不同,也就是一开始开人不一样,需要注意一下。

【代码】

#include <bits/stdc++.h>

#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define REP(i, s, t) for (int i = s; i <= t; i++)
#define PER(i, s, t) for (int i = s; i >= t; i--)
#define FI first
#define SE second
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

template <class T>
void rd(T& x) {
  x = 0; char ch = 0; int f = 1;
  for (; !isdigit(ch); ch = getchar())
    if (ch == '-')
      f = -1;
  for (; isdigit(ch); ch = getchar())
    x = x * 10 + ch - 48;
  x *= f;
}

template<class T>
void pr(T x){
  if (!x) {
    putchar('0');
    return;
  }
  if (x < 0)
    putchar('-'), x = -x;
  static int stk[25], top; top=0;
  while (x)
    stk[++top] = x % 10, x /=10;
  while(top)
    putchar(stk[top--] + 48);
}

const int N = 1e5 + 5;
const int MG = 27;
const double eps = 1e-7;

int n;
int h[N];
set<pii> st;
int ga[N], gb[N];
int f[MG][N][2], da[MG][N][2], db[MG][N][2];

// f[2 ^ i days][start at j city][first driver is (a = 0, b = 1)] to city
// da[2 ^ i days][start at j city][first driver is (a = 0, b = 1)] distance of a
// db[2 ^ i days][start at j city][first driver is (a = 0, b = 1)] distance of b

int getDis(int i, int j) {
  return abs(h[i] - h[j]);
}

bool equal(double x, double y) {
  return x - y <= eps;
}

void preWork() {
  st.insert(mp(inf, 0)), st.insert(mp(inf, 0));
  st.insert(mp(-inf, 0)), st.insert(mp(-inf, 0));
  h[0] = inf;
  for (int i = n; i >= 1; i--) {
    st.insert(mp(h[i], i));
    set<pii>::iterator it, it1, it2, it3, it4;
    it = st.find(mp(h[i], i));
    ++it; it1 = it; ++it; it2 = it;
    it = st.find(mp(h[i], i));
    --it; it3 = it; --it; it4 = it;
    if (getDis((*it1).SE, i) < getDis((*it3).SE, i)) {
      gb[i] = (*it1).SE;
      if (getDis((*it2).SE, i) < getDis((*it3).SE, i))
        ga[i] = (*it2).SE;
      else
        ga[i] = (*it3).SE;
    } else {
      gb[i] = (*it3).SE;
      if (getDis((*it1).SE, i) < getDis((*it4).SE, i))
        ga[i] = (*it1).SE;
      else
        ga[i] = (*it4).SE;
    }
  }
  for (int i = 1; i <= n; i++) {
    f[0][i][0] = ga[i], f[0][i][1] = gb[i];
    da[0][i][0] = getDis(i, ga[i]), da[0][i][1] = 0;
    db[0][i][0] = 0, db[0][i][1] = getDis(i, gb[i]);
  }
  for (int j = 1; j <= n; j++)
    for (int k = 0; k <= 1; k++) {
      f[1][j][k] = f[0][f[0][j][k]][k ^ 1];
      da[1][j][k] = da[0][j][k] + da[0][f[0][j][k]][k ^ 1];
      db[1][j][k] = db[0][j][k] + db[0][f[0][j][k]][k ^ 1];
    }
  for (int i = 2; i <= 24; i++)
    for (int j = 1; j <= n; j++)
      for (int k = 0; k <= 1; k++) {
        f[i][j][k] = f[i - 1][f[i - 1][j][k]][k];
        da[i][j][k] = da[i - 1][j][k] + da[i - 1][f[i - 1][j][k]][k];
        db[i][j][k] = db[i - 1][j][k] + db[i - 1][f[i - 1][j][k]][k];
      }
}

pii calc(int u, int x) {
  pii res = {0, 0};
  for (int i = 24; i >= 0; i--)
    if (f[i][u][0] && res.FI + res.SE + da[i][u][0] + db[i][u][0] <= x)
      res.FI += da[i][u][0], res.SE += db[i][u][0], u = f[i][u][0];
  return res;
}

void solve1() {
  int x0; rd(x0);
  pair<pii, int> res = mp(calc(1, x0), 1);
  for (int i = 2; i <= n; i++) {
    pii tmp = calc(i, x0);
    if (tmp.SE == 0)
      continue;
    else if ((res.FI.SE == 0) || (1.0 * tmp.FI / tmp.SE < 1.0 * res.FI.FI / res.FI.SE) || (equal(1.0 * tmp.FI / tmp.SE, 1.0 * res.FI.FI / res.FI.SE) && (h[res.FI.SE] < h[tmp.SE])))
      res = mp(tmp, i);
  }
  pr(res.SE), puts("");
}

void solve2() {
  int m; rd(m);
  while (m--) {
    int s0, x0; rd(s0), rd(x0);
    pii tmp = calc(s0, x0);
    pr(tmp.FI), putchar(' '), pr(tmp.SE), puts("");
  }
}

int main() {
#ifndef ONLINE_JUDGE
  freopen("a.in", "r", stdin);
  freopen("a.out", "w", stdout);
#endif
  rd(n);
  for (int i = 1; i <= n; i++)
    rd(h[i]);
  preWork();
  solve1(), solve2();
  return 0;
}

【LOJ2604】「NOIP2012」开车旅行的更多相关文章

  1. 「NOIP2012」开车旅行

    传送门 Luogu 解题思路 第一步预处理每个点后面的最近点和次近点,然后就是模拟题意. 但是如果就这么搞是 \(O(N^2)\) 的,不过可以过70分,考场上也已经比较可观了. 考虑优化. 预处理最 ...

  2. Loj #3057. 「HNOI2019」校园旅行

    Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...

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

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

  4. 【NOIP2012】开车旅行(倍增)

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

  5. vijos P1780 【NOIP2012】 开车旅行

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

  6. 【vijos1780】【NOIP2012】开车旅行 倍增

    题目描述 有\(n\)个城市,第\(i\)个城市的海拔为\(h_i\)且这\(n\)个城市的海拔互不相同.编号比较大的城市在东边.两个城市\(i,j\)之间的距离为\(|h_i-h_j|\) 小A和小 ...

  7. noip2012 P1081 开车旅行

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

  8. 【noip2012】开车旅行

    题意: 给n个点的海拔h[i](不同点海拔不同) 两点的距离为abs(h[i]-h[j]) 有a.b两人轮流开车(只能往下标大的地方开) a每次会开到里当前点第二近的点 b每次会开到离当前点最近的点( ...

  9. 「luogu3313」[SDOI2014] 旅行

    题目大意 :有 n 个城市连成一棵树, 每个城市有两个关键字, 一个是该城市的宗教, 另一个是城市的评级;旅行者要在城市间旅行, 他只会在和自己宗教相同的城市留宿;维护四个树上操作 { 1. “CC ...

随机推荐

  1. [转帖]2015年时的新闻:Debian GNU/Hurd 2015 发布

    Debian GNU/Hurd 2015 发布 oschina 发布于 2015年04月30日 https://www.oschina.net/news/62004/debian-gnu-hurd-2 ...

  2. [转帖]备忘:CentOS-7 使用systemctl 管理的服务,文件打开数上限1024要改

    备忘:CentOS-7 使用systemctl 管理的服务,文件打开数上限1024要改 https://blog.csdn.net/toontong/article/details/50440272 ...

  3. Codeforces 1237E Perfect Balanced Binary Search Tree

    题目链接 Observations 含有 $n$ 个点且 key(以下也称 key 为「权值」)是 1 到 $n$ 的 BST 具有下列性质: 若 $k$ 是一个非根叶子且是个左儿子,则 $k$ 的父 ...

  4. P4942小凯的数字

    给定一个序列,如12345 56789 1011121314等,输出对其取余9的结果. 那么我们需要明白一个定理,一个序列对一个数的取余结果等于它各位之和取余那个数的结果.证明似乎是这样∑i=0n​a ...

  5. Java设计模式之外观模式和最少知识原则

    外观模式: 外观模式:提供一个统一的接口,来访问子系统中一群功能相关接口(类似一键启动,一键关闭等等) 外观模式定义了一个高层接口,让子系统更容易使用 降低对外接口耦合度 外观模式和命令模式各自侧重点 ...

  6. python-day38(正式学习)

    目录 线程 线程开启的两种方式 1 2 子线程和子进程的创建速度 子线程共享资源 线程的join方法 守护线程 线程其他用法 线程 线程开启的两种方式 1 from threading import ...

  7. 解决Sublime Text3中文符号以及中文显示乱码问题

    今天安装了sublime Text3,发现中文符号显示是乱码,刚开始以为是编码问题,经过各种尝试,终于找到了解决办法.解决方法如下: 一.安装包管理器 使用Ctrl+~快捷键或者通过View-> ...

  8. 111、什么是stack (Swarm18)

    参考https://www.cnblogs.com/CloudMan6/p/8119150.html   什么是 stack ?    在将这个之前先回顾一下前面部署WordPress的过程:     ...

  9. 利用yaml文件管理资源

    利用yaml配置文件管理资源 [root@master ~]# cat nginx-deployment.yaml apiVersion: apps/v1beta2 kind: Deployment ...

  10. 【Activiti】crm与工作流的整合,一个完整的流程实例创建到任务完成的过程

    1.建立任务列表页面--根据用户的nickName作为assignee查询其所拥有的任务列表 2.在任务后添加办理按钮 3.点击办理按钮,出现流程办理框,其中详细显示了该任务的相关详细信息,本实例中为 ...