zoukankan      html  css  js  c++  java
  • P1081 开车旅行

    题意:

    小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 11 到 NN 编号,且编号较小的城市在编号较大的城市的西边,

    已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 $H_i$​ ,城市 i 和城市 j 之间的距离 $d_{[i,j]}=|H_i-H_j|$ 。

    旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次。

    他们计划选择一个城市 SS 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行。

    小 A 和小 B 的驾驶风格不同,小 B 总是沿着前进方向选择一个最近的城市作为目的地,而小 A 总是沿着前进方向选择第二近的城市作为目的地

    (注意:本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。

    如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出 X 公里,他们就会结束旅行。

    在启程之前,小 A 想知道两个问题:

    1:对于一个给定的 $X=X_0$​ ,从哪一个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小(如果小 B 的行驶路程为 0 ,此时的比值可视为无穷大,且两个无穷大视为相等)。

      如果从多个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值都最小,则输出海拔最高的那个城市。

    2:对任意给定的 $X=X_i$​ 和出发城市 $S_i$​ ,小 A 开车行驶的路程总数以及小 B 行驶的路程总数。

    以f[i][j]记录从i点经过$2^j$轮后他们所到的点

    以disa[i][j]记录a从i点经过$2^j$天自己走的距离

    以disb[i][j]记录b从i点经过$2^j$天自己走的距离

    以ato[i]记录a从i点走一步所到的点

    以bto[i]记录b从i点走一步所到的点

    首先,把所有城市按海拔排序,并建立排序前后的映射

    从第一个城市开始枚举,那么所有的城市都在它的东边

    然后对应到排序好的城市中,处理出ato[i],bto[i]

    处理完把当前城市删除,第二个变成第一个,因此再次求的时候仍然所有点都在东边

    之后处理st表,模拟即可

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    #define int long long
    #define olinr return
    #define _ 0
    #define nmr 105050
    #define love_nmr 0
    #define DB double
    int n;
    struct node
    {
        int pre;
        int nxt;
        int h;
        int id;
        friend bool operator < (const node &a,const node &b)
        {
            return a.h<b.h;
        }
    }s[nmr];
    int disa[nmr][31];
    int disb[nmr][31];
    int f[nmr][31];
    int ato[nmr];
    int bto[nmr];
    int X;
    int m;
    int mp[nmr];
    int ans;
    DB minn=0x7fffffff;
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')
                f=-f;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    inline void put(int x)
    {
        if(x<0)
        {
            x=-x;
            putchar('-');
        }
        if(x>9)
            put(x/10);
        putchar(x%10+'0');
    }
    inline int abss(int x)
    {
        if(x<0) return -x;
        return x;
    } 
    inline bool near_left(int now,int l,int r)
    {
        if(!l) return false;
        if(!r) return true;
        int disl=abss(s[l].h-s[now].h);
        int disr=abss(s[r].h-s[now].h);
        if(disl<disr) return true;
        if(disl>disr) return false;
        return s[l].h<s[r].h;
    }
    inline int opposite(int now,int l,int r)
    {
        if(!l) return s[r].id;
        if(!r) return s[l].id;
        int disl=abss(s[l].h-s[now].h);
        int disr=abss(s[r].h-s[now].h);
        if(disl<disr) return s[l].id;
        if(disl>disr) return s[r].id;
        if(s[l].h<s[r].h) return s[l].id;
        return s[r].id;
    }
    inline void beizeng()
    {
        for(int i=1;i<=n;i++)   //a---->b---->c
        {
            f[i][0]=bto[ato[i]];   //a---->c
            disa[i][0]=abss(s[mp[i]].h-s[mp[ato[i]]].h);   //a---->b
            disb[i][0]=abss(s[mp[f[i][0]]].h-s[mp[ato[i]]].h);  //b---->c
        }
        for(int j=1;j<=23;j++)
            for(int i=1;i<=n;i++)
            {
                f[i][j]=f[f[i][j-1]][j-1];
                disa[i][j]=disa[i][j-1]+disa[f[i][j-1]][j-1];
                disb[i][j]=disb[i][j-1]+disb[f[i][j-1]][j-1];
            }
    }
    inline void running(int sta,int &a,int &b,int limit)
    {
        for(int i=22;i>=0;i--)
        {
            if(f[sta][i]&&(a+b+disa[sta][i]+disb[sta][i])<=limit)  //模拟倍增过程,A、B一起跑
            {
                a+=disa[sta][i];
                b+=disb[sta][i];
                sta=f[sta][i];
            }
        }
        if(ato[sta]&&(a+b+disa[sta][0])<=limit) //现在AB同时跑不行,但可以看看A单独跑行不行!!
            a+=disa[sta][0];
    }
    signed main()
    {
        n=read();
        for(int i=1;i<=n;i++)
        {
            s[i].h=read();
            s[i].id=i;
        }
        sort(s+1,s+n+1);
        for(int i=1;i<=n;i++)
        {
            s[i].pre=i-1;
            s[i].nxt=i+1;
            mp[s[i].id]=i;       //排序前后映射
        }
        s[n].nxt=s[1].pre=0;      //排序后的左右
        for(int i=1;i<=n;i++)
        {
            int pos=mp[i];
            int l=s[pos].pre;      //此时l,r都在当前的东边!
            int r=s[pos].nxt;        
            if(near_left(pos,l,r))    //判断左边是否最近
            {
                bto[i]=s[l].id;
                ato[i]=opposite(pos,s[l].pre,r);   //若左边近,用左边的左边和右边比次近
            }
            else
            {
                bto[i]=s[r].id;
                ato[i]=opposite(pos,l,s[r].nxt);
            }
            if(r) s[r].pre=l;    //用完把当前删掉,保证下一个是最西边的
            if(l) s[l].nxt=r;
        }
        beizeng();   //倍增预处理
        X=read();
        m=read();
        for(int i=1;i<=n;i++)
        {
            int tota=0;
            int totb=0;
            running(i,tota,totb,X);
            if(totb&&(((DB)tota/(DB)totb)<minn))
            {
                minn=(DB)tota/(DB)totb;
                ans=i;
            }
        }
        if(ans==0) ans=s[n].id;
        put(ans);
        putchar('
    ');
        for(int i=1;i<=m;i++)
        {
            int sta,limit;
            sta=read();
            limit=read();
            int tota=0;
            int totb=0;
            running(sta,tota,totb,limit);
            put(tota);
            putchar(' ');
            put(totb);
            putchar('
    ');
        }
        olinr ~~(0^_^0)+love_nmr;
    }
  • 相关阅读:
    MQTT TLS 加密传输
    python多进程并发redis
    各种消息队列的特点
    mqtt异步publish方法
    Numpy API Analysis
    Karma install steps for unit test of Angular JS app
    reinstall bower command
    Simulate getter in JavaScript by valueOf and toString method
    How to: Raise and Consume Events
    获取对象的类型信息 (JavaScript)
  • 原文地址:https://www.cnblogs.com/olinr/p/9535528.html
Copyright © 2011-2022 走看看