题解 P1081 【开车旅行】

Solution 开车旅行

题目大意:有\(n\)座城市,每座城市有一个海拔高度,你只能从编号小的往编号大的移动。定义两城市距离为海拔高度差的绝对值。小A开车会去离他第二近的城市,小B开车会去离他最近的城市。(如果距离相同则认为海拔低的近)。两人开车的距离之和不能超过\(X\),问给定一个\(X\)从哪座城市出发小A小B行驶距离之比最小,(一样小的认为海拔高的小),问给定出发点\(s\)和\(X\),小A小B分别行驶距离

倍增



分析:首先关键在于给定\(s\)和\(X\)的时候快速算出他俩分别走了多远,这样第一问就可以枚举来回答

不难想到暴力算法,我们把A,B都走一次称为一轮,那么我们一轮一轮的走,直到走不动为止。因为A先走所以最后单独考虑A即可

这样的时间复杂度单次\(O(n)\),无法承受。我们关注点在一轮一轮的走太花时间,因此我们可以倍增来走,单次时间复杂度降至\(O(logn)\)

麻烦的地方在于预处理A和B会走到哪儿,不难想到,假如我们对于序列每一个后缀建一棵平衡树,那么小B就是在前驱和后继里面取最优。小A就是加上前驱的前驱,后继的后继然后取次优,这个我们用\(set\)来维护,\(vector\)暴力排序即可(反正最多只有\(4\)个元素)

然后关于倍增,我们预处理出从每个位置\(pos\)走\(2^i\)次方轮后走到哪儿,其中A走了多远,B走了多远即可

代码要开C++11

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100,maxd = 25;
inline int read(){
    int x = 0,f = 1;char c = getchar();
    while(!isdigit(c))f = c == '-' ? -1 : f,c = getchar();
    while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    return x * f;
}
struct SetNode{
    int pos,v;
    bool operator < (const SetNode &rhs)const{
        return v < rhs.v;
    }
};
int val[maxn],nxtA[maxn],nxtB[maxn],nxt[maxn][maxd + 1],n,m,X0,s,x,ans;
long double tmp;
ll disA[maxn][maxd + 1],disB[maxn][maxd + 1];
inline int getdis(int a,int b){return abs(val[a] - val[b]);}
inline void init(){
    set<SetNode> s;
    vector<SetNode> vec;
    typedef set<SetNode>::iterator iter;
    auto getpre = [&](iter x){return x == s.begin() ? x : --x;};
    auto getnxt = [&](iter x){return x == s.end() ? x : ++x;};
    for(int i = n;i >= 1;i--){
        iter tmp = s.upper_bound(SetNode{0,val[i]});
        for(auto it = getpre(getpre(getpre(tmp)));it != getnxt(getnxt(getnxt(tmp)));it++)
            vec.push_back(*it);
        sort(vec.begin(),vec.end(),[&](const SetNode &a,const SetNode &b){
            int ta = abs(val[i] - a.v),tb = abs(val[i] - b.v);
            return ta == tb ? a.v < b.v : ta < tb;
        });
        nxtA[i] = vec.size() >= 2 ? vec[1].pos : -1;
        nxtB[i] = vec.size() >= 1 ? vec[0].pos : -1;
        s.insert(SetNode{i,val[i]});
        vec.clear();
    }
    for(int i = 1;i <= n;i++){
        nxt[i][0] = nxtA[i] == -1 ? -1 : (nxtB[nxtA[i]] == -1 ? -1 : nxtB[nxtA[i]]);
        disA[i][0] = nxtA[i] == -1 ? -1 : getdis(i,nxtA[i]);
        disB[i][0] = nxtA[i] == -1 ? -1 : (nxtB[nxtA[i]] == -1 ? -1 : getdis(nxtA[i],nxtB[nxtA[i]]));
    }
    for(int d = 1;d <= maxd;d++)
        for(int i = 1;i <= n;i++){
            nxt[i][d] = nxt[i][d - 1] == -1 ? -1 : (nxt[nxt[i][d - 1]][d - 1] == -1 ? -1 : nxt[nxt[i][d - 1]][d - 1]);
            disA[i][d] = nxt[i][d] == -1 ? -1 : (disA[i][d - 1] + (nxt[i][d - 1] == -1 ? 0 : disA[nxt[i][d - 1]][d - 1]));
            disB[i][d] = nxt[i][d] == -1 ? -1 : (disB[i][d - 1] + (nxt[i][d - 1] == -1 ? 0 : disB[nxt[i][d - 1]][d - 1]));
        }
}
inline long double solve1(int pos){
    x = X0;
    ll resA = 0,resB = 0;
    for(int d = maxd;d >= 0;d--)
        if((x >= disA[pos][d] + disB[pos][d]) && nxt[pos][d] != -1 && disA[pos][d] != -1 && disB[pos][d] != -1)
            resA += disA[pos][d],resB += disB[pos][d],x -= disA[pos][d] + disB[pos][d],pos = nxt[pos][d];

    if(disA[pos][0] != -1 && x >= disA[pos][0])resA += disA[pos][0];
    return !resB ? (1e18) : (long double)resA / resB;
}
inline void solve2(){
    ll ansA = 0,ansB = 0;
    for(int d = maxd;d >= 0;d--)
        if((x >= disA[s][d] + disB[s][d]) && nxt[s][d] != -1 && disA[s][d] != -1 && disB[s][d] != -1)
            ansA += disA[s][d],ansB += disB[s][d],x -= disA[s][d] + disB[s][d],s = nxt[s][d];

    if(disA[s][0] != -1 && x >= disA[s][0])ansA += disA[s][0];
    printf("%lld %lld\n",ansA,ansB);
}
int main(){
    n = read();
    for(int i = 1;i <= n;i++)val[i] = read();
    init();
    X0 = read();
    for(int i = 1;i <= n;i++){
        long double t = solve1(i);
        if(!ans || (t == tmp ? (val[i] > val[ans]) : (t < tmp)))
            ans = i,tmp = t;
    }
    printf("%d\n",ans);
    m = read();
    for(int i = 1;i <= m;i++)
        s = read(),x = read(),solve2();
    return 0;
}

原文地址:https://www.cnblogs.com/colazcy/p/11718962.html

时间: 2024-10-09 02:19:03

题解 P1081 【开车旅行】的相关文章

洛谷P1081 开车旅行

P1081 开车旅行 152通过 524提交 题目提供者洛谷OnlineJudge 标签倍增NOIp提高组2012 难度省选/NOI- 提交该题 讨论 题解 记录 最新讨论 我前排提醒一下 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi−

【题解】开车旅行

开车旅行 (drive.cpp/c/pas) [问题描述] 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i, j] = |???? − ????|. 旅行过程中,小A 和小B轮流开车,第一天小A 开车,之后每天轮换一次.他们计划选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X

[NOIP2012] 提高组 洛谷P1081 开车旅行

题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi− Hj|. 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次.他们计划 选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行.小 A 和小 B

P1081 开车旅行(Not Finish)

https://www.luogu.org/problemnew/show/P1081 原文地址:https://www.cnblogs.com/mzg1805/p/10422175.html

P1081 开车旅行[倍增](毒瘤题)

其实就是个大模拟. 首先,根据题意,小A和小B从任意一个城市开始走,无论\(X\)如何,其路径是一定唯一的. 显然对于两问都可以想出一个\(O(n^2)\)的暴力,即直接一步一步地向右走. 首先,我们当然需要知道A,B在每个城市的下一步如何走,记\(nexta(i),nextb(i)\)为A,B在\(i\)处时,下一步走到的城市编号. 考虑如何高效(复杂度小于等于\(O(nlogn)\))维护两个\(next\). 显然不能直接维护每个城市与其后面的城市的差值,再好的数据结构也会到\(O(n^2

P1081 开车旅行

______________________________________________________________________________________________________________________ 做法来自lyd书 双向链表初始化,倍增优化DP // luogu-judger-enable-o2 #include<bits/stdc++.h> using namespace std; long long la,lb; int n,t,x0,ans,m;

noip2012 开车旅行

P1081 开车旅行 139通过 484提交 题目提供者洛谷OnlineJudge 标签倍增2012NOIp提高组 难度提高+/省选- 提交该题 讨论 题解 记录 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi− Hj|. 旅行过程中,小

开车旅行

洛谷P1081 开车旅行  NOIP 2012 提高组 第一天 第三题 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi− Hj|. 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次.他们计划 选择一个城市 S 作

codevs 1199 开车旅行 2012年NOIP全国联赛提高组

1199 开车旅行 2012年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i, j] = |Hi − Hj|. 旅行过程中,小A 和小B轮流开