zoukankan      html  css  js  c++  java
  • 开车旅行(2012day1T3)

    倍增

    原文链接【luogu】https://www.luogu.org/problem/P1081

    【题目描述】

    小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市i和城市j之间的距离d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i,j]=|Hi−Hj|。

    旅行过程中,小A和小B轮流开车,第一天小A开车,之后每天轮换一次。他们计划选择一个城市S作为起点,一直向东行驶,并且最多行驶X公里就结束旅行。小A和小B的驾驶风格不同,小B总是沿着前进方向选择一个最近的城市作为目的地,而小A总是沿着前进方向选择第二近的城市作为目的地(本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出X公里,他们就会结束旅行。

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

    (1)对于一个给定的X=X0,从哪一个城市出发,小A开车行驶的路程总数与小B行驶的路程总数的比值最小(如果小B的行驶路程为0,此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小A开车行驶的路程总数与小B行驶的路程总数的比值都最小,则输出海拔最高的那个城市。

    (2)对任意给定的X=Xi和出发城市Si,小A开车行驶的路程总数以及小B行驶的路程总数。

    【输入描述】

    第一行包含一个整数N,表示城市的数目;

    第二行有N个整数,每两个整数之间用一个空格隔开,依次表示城市1到城市N的海拔高度,即H1、H2、······、Hn,且每个Hi都是不同的;

    第三行包含一个整数X0;

    第四行为一个整数M,表示给定M组Si和Xi;

    接下来的M行,每行包含2个整数Si和Xi,表示从城市Si出发,最多行驶Xi公里。

    【输出描述】

    输出共M+1行;

    第一行包含一个整数S0,表示对于给定的X0,从编号为S0的城市出发,小A开车行驶的路程总数与小B行驶的路程总数的比值最小;

    接下来的M行,每行包含2个整数,之间用一个空格隔开,依次表示在给定的Si和Xi下小A行驶的里程总数和小B行驶的里程总数。

    【样例输入】

    样例1:

    4

    2 3 1 4

    3

    4

    1 3

    2 3

    3 3

    4 3

    样例2:

    10

    4 5 6 1 2 3 7 8 9 10

    7

    10

    1 7

    2 7

    3 7

    4 7

    5 7

    6 7

    7 7

    8 7

    9 7

    10 7

    【样例输出】

    样例1:

    1

    1 1

    2 0

    0 0

    0 0

    样例2:

    2

    3 2

    2 4

    2 1

    2 4

    5 1

    5 1

    2 1

    2 0

    0 0

    0 0

     

     强烈吐槽预处理,还有随时溢出的long long

    #include<bits/stdc++.h>
    #define re return
    #define ll long long
    #define inc(i,l,r) for(int i=l;i<=r;++i)
    #define dec(i,l,r) for(int i=l;i>=r;--i)
    
    const ll maxn=100005,inf=1e11;
    using namespace std;
    template<typename T>inline void rd(T&x)
    {
        char c;bool f=0;
        while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
        x=c^48;
        while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
        if(f)x=-x;
    }
    
    ll n,pos[maxn],nt[maxn][2];
    ll f[maxn][28],ff[maxn],dis[maxn][28][2],dd[maxn];
    double ans,da,db;
    
    struct node{
        ll val;
        int id,lf,rf;
        bool operator<(node a)const 
        {
            re val<a.val;
        }
    }h[maxn];
    
    inline int check(int x,int y,int z)//检查较近城市 
    {
        if(abs(h[x].val-h[z].val)<=abs(h[y].val-h[z].val))re x;
        re y;
    }
    
    //---------------------------预处理-------------------------
    inline void Pre()
    {
        sort(h+1,h+n+1);
        inc(i,1,n)
        {
            pos[h[i].id]=i;
            h[i].lf=i-1;
            h[i].rf=i+1;    
        }
        
        //双向链表排序 
        int l,r;
        inc(i,1,n-1)
        {
            int p=pos[i];
            l=h[p].lf;r=h[p].rf;
            nt[i][1]=check(l,r,p);//小B向最近点开 
            if(nt[i][1]==l)nt[i][0]=check(h[l].lf,r,p);
            else nt[i][0]=check(l,h[r].rf,p);
            
            
            //初始化第一天 
            if(nt[i][0])
            {
                f[i][0]=h[nt[i][0]].id;
                dis[i][0][0]=abs(h[nt[i][0]].val-h[p].val);
            }
            if(nt[i][1])
            {
                ff[i]=h[nt[i][1]].id;
                dd[i]=abs(h[nt[i][1]].val-h[p].val);
            }
            if(l)h[l].rf=r;
            if(r)h[r].lf=l;
        }
    }
    
    //-----------------------倍增-------------------------
    inline void Bz()
    {
        inc(i,1,n)
        {
            f[i][1]=ff[f[i][0]];
            dis[i][1][0]=dis[i][0][0];
            dis[i][1][1]=dd[f[i][0]];
            //第一天小A开,则第二天小B开 
        }
        
        inc(j,2,27)
        inc(i,1,n)
        {
            //以此类推
            //第4,8,16……天开完,仍是小A开 
            f[i][j]=f[f[i][j-1]][j-1];
            dis[i][j][0]=dis[i][j-1][0]+dis[f[i][j-1]][j-1][0];
            dis[i][j][1]=dis[i][j-1][1]+dis[f[i][j-1]][j-1][1];
        }
    }
    
    //------------------------倍增查询小A小B走过路程----------------------------
    inline void ask(ll x,int a)
    {
        dec(i,27,0)
        if(f[a][i]&&x>=dis[a][i][0]+dis[a][i][1])
        {
            x=x-dis[a][i][0]-dis[a][i][1];
            da+=dis[a][i][0];
            db+=dis[a][i][1];
            a=f[a][i]; 
        }
    }
    
    inline void X0()
    {
        int x,ansp=0;
        ans=inf;
        //ans为比值
        //ansp为最佳位置 
        rd(x);
        inc(i,1,n)
        {
            da=db=0;
            //da为小A走过的路程
            //db为小B走过的路程 
            ask(x,i);
            if(db==0)
            {
                if(ans==inf&&h[pos[i]].val>h[pos[ansp]].val)
                ansp=i;
            }
            else if(da/db<ans)ans=da/db,ansp=i;
            else if(da/db==ans&&h[pos[i]].val>h[pos[ansp]].val)
            ans=da/db,ansp=i;
        }
        printf("%d
    ",ansp);
    }
    int main()
    {
        freopen("in.txt","r",stdin); 
        h[0].val=-inf;
        rd(n);
        inc(i,1,n)
        {
            rd(h[i].val);
            h[i].id=i;
        }
        h[n].rf=0;
        Pre();
        Bz();
        X0();
        
        int x,opt;
        rd(n);
        while(n--)
        {
            da=db=0;
            rd(opt),rd(x);
            ask(x,opt);
            printf("%.0lf %.0lf
    ",da,db);
        }
        re 0;
    }
  • 相关阅读:
    JS 中 new 操作符
    js清除浏览器缓存的几种方法
    一个自定义分享按钮
    解决windows下nginx中文文件名乱码
    sublime text 3 添加 javascript 代码片段 ( snippet )
    transition动画最简使用方式
    hammerjs jquery的选项使用方法,以给swipe设置threshold和velocity为例
    sublime text 3 的emmet 添加自定义 html 片段
    解决 placeholder 垂直不居中,偏上的问题
    Sublime Text 3 配置 sass
  • 原文地址:https://www.cnblogs.com/lsyyy/p/11334960.html
Copyright © 2011-2022 走看看