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

    开车旅行

    有n个东西向成一排的城市,自西向东编号为1~n,第i个城市的高度为(h_i),高度互不相同,定义两个城市i,j的距离(dis(i,j)=|h_i-h_j|)(大小的比较优先值,当值相同时,比较高度的大小),现在有两个人a,b在同一辆车从某个城市出发向东移动,并轮流开车,第一天a开车,a每天开车选择到达离它次近的城市,而b选择到离他最近的城市,现在有两种询问:

    询问一:

    给出x,询问从哪个城市出发,使行驶总距离不超过x,且a行驶的距离与b行驶的距离比值最大(分母为0算无限大,比值相同选高度最高的城市s)。

    询问二:

    有m组询问,每组询问有一个s,x,表示出发城市为s,求行驶总距离不超过x的情况下,a,b分别行驶的距离。

    对于100%的数据,有(1≤N≤100,000,1≤M≤100,000)

    其实最大的特点是发现一个确定的人在一个确定的位置,所能到达的下一个城市是固定的,而这是倍增的标志。

    对于一个城市i,东边离它最近的城市自然是高度离它最近的,要维护则是把东边的城市和该城市排序后取这个城市附近的位置,而涉及要维护排序,自然是平衡树,因为还未学,所以set替代,注意先加入数在找其附近更好实现,次近同理。

    于是设(Ag[i])表示a在第i个城市所能到达的城市编号,同理有(Bg[i]),上诉已阐述维护办法,接着自然要求出(go[i][j][k])表示在第i个城市,经过(2^j)天,人k(0A,1B)在头一天出发后到达的城市,不难有

    [go[i][0][0]=Ag[i],go[i][0][1]=Bg[i] ]

    [go[i][1][k]=go[go[i][0][k]][0][1-k] ]

    [go[i][j][k]=go[go[i][j-1][k]][j-1][k] ]

    除了提到的,其他全部为0

    接着我们要维护(A[i][j][k],B[i][j][k])分别表示在第i个城市出发,经过(2^j)天,人k头天出发a行驶的距离,b行驶的距离,先全部初始化无限大

    现在有

    [A[i][0][0]=dis(i,go[i][0][0]),A[i][0][1]=0 ]

    [A[i][1][k]=A[i][0][k]+A[go[i][0][k]][0][1-k] ]

    [A[i][j][k]=A[i][j-1][k]+A[go[i][j-1][k]][j-1][k] ]

    [B[i][0][0]=0,B[i][0][1]=dis(i,go[i][0][1]) ]

    [B[i][1][k]=B[i][0][k]+B[go[i][0][k]][0][1-k] ]

    [B[i][j][k]=B[i][j-1][k]+B[go[i][j-1][k]][j-1][k] ]

    于是我们维护好了倍增数组,现在考虑如何回答询问,首先建立一个ask函数,给定s,x(同第二种询问变量意思),回答a,b分别行驶的距离,而对于不超过x,我们可以利用而二进制拆分,从大到小枚举接近答案,因此第二种询问也就解决了,时间复杂度(log_2^n)

    而对于第一种询问,不难得知,我们可以支持枚举哪个城市,直接暴力算出比值,一个一个比即可。

    因此问题得以解决,此题展示了倍增的交替使用,不妨叫做交替倍增,还考了常见的先维护位置倍增,再维护距离倍增,二进制拆分查询答案的方法,还有注意的事对stl的使用,如set。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <set>
    #include <algorithm>
    #define il inline
    #define ri register
    #define ll long long
    #define swap(x,y) x^=y^=x^=y
    #define Size 100000
    #define intmax 0x7fffffff
    using namespace std;
    struct frac{
        int s,m;
        il void sort(){
            int d(gcd(s,m));
            if(d)s/=d,m/=d;
        }
        il int gcd(int a,int b){
            while(b)swap(a,b),b%=a;return a;
        }
        il bool operator==(frac&x){
            if(!x.m&&!m)return true;
            if(x.m==m&&s==x.s)return true;
            return false;
        }
        il bool operator<(frac&x){
            if(!m)return false;if(!x.m)return true;
            return (double)s/m<(double)x.s/x.m;
        }
    }r1,r2;
    struct pi{
        int x,y;
        il bool operator<(const pi&a)const{
            return x<a.x;
        }
    }m,g[5];int gt;
    set<pi>H;
    set<pi>::iterator l,r;
    ll A[Size+1][18][2],B[Size+1][18][2];
    int Ag[Size+1],Bg[Size+1],go[Size+1][18][2],h[Size+1];
    il pi ask(int,int);
    il void prepare(int);
    il bool comp(const pi&,const pi&);
    template<class free>il free Abs(free);
    template<class free>il void read(free&);
    int main(){
        int n,s,x;
        read(n),prepare(n),read(x);
        for(int i(1);i<=n;++i){
            m=ask(i,x);
            r1=(frac){m.x,m.y},r1.sort();
            if(r1<r2)r2=r1,s=i;
            else if(r1==r2&&h[s]<h[i])s=i;
        }printf("%d
    ",s),read(n);
        while(n--)
            read(s),read(x),m=ask(s,x),
                printf("%d %d
    ",m.x,m.y);
        return 0;
    }
    il void prepare(int n){
        for(int i(1);i<=n;++i)read(h[i]);
        for(int i(n),j;i;--i){
            j=h[i],m=(pi){j,i},gt&=0;
            H.insert(m),l=r=H.find(m);
            if(l!=H.begin()){
                --l,g[++gt]=*l;
                if(l!=H.begin())--l,g[++gt]=*l;
            }
            if(++r,r!=H.end()){
                g[++gt]=*r;
                if(++r,r!=H.end())g[++gt]=*r;
            }sort(g+1,g+gt+1,comp);
            if(gt>=2)Ag[i]=g[2].y;
            if(gt>=1)Bg[i]=g[1].y;
        }h[0]=intmax;
        for(int i(n),j;i;--i){
            go[i][0][0]=Ag[i],go[i][0][1]=Bg[i];
            for(j=0;j<2;++j)go[i][1][j]=go[go[i][0][j]][0][1-j];
            for(j=2;j<18;++j)
                go[i][j][0]=go[go[i][j-1][0]][j-1][0],
                    go[i][j][1]=go[go[i][j-1][1]][j-1][1];
        }memset(A,1,sizeof(A)),memset(B,1,sizeof(B));
        for(int i(n),j,k;i;--i){
            A[i][0][0]=Abs(h[go[i][0][0]]-h[i]),A[i][0][1]=0;
            B[i][0][0]=0,B[i][0][1]=Abs(h[go[i][0][1]]-h[i]);
            for(j=0;j<2;++j){
                A[i][1][j]=A[i][0][j]+A[go[i][0][j]][0][1-j];
                B[i][1][j]=B[i][0][j]+B[go[i][0][j]][0][1-j];
            }
            for(j=2;j<18;++j)
                for(k=0;k<2;++k){
                    A[i][j][k]=A[i][j-1][k]+A[go[i][j-1][k]][j-1][k];
                    B[i][j][k]=B[i][j-1][k]+B[go[i][j-1][k]][j-1][k];
                }
        }
    }
    il pi ask(int p,int x){
        int la(0),lb(0);
        for(int i(17);i>=0;--i)
            if(x>=A[p][i][0]+B[p][i][0])
                la+=A[p][i][0],lb+=B[p][i][0],
                    x-=A[p][i][0]+B[p][i][0],p=go[p][i][0];
        return (pi){la,lb};
    }
    il bool comp(const pi&a,const pi&b){
        return Abs(a.x-m.x)==Abs(b.x-m.x)?
            a.x<b.x:Abs(a.x-m.x)<Abs(b.x-m.x);
    }
    template<class free>
    il free Abs(free x){
        return x<0?-x:x;
    }
    template<class free>
    il void read(free&x){
        x&=0;ri char c;while(c=getchar(),c==' '||c=='
    '||c=='
    ');
        ri bool check(false);if(c=='-')check|=true,c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        if(check)x=-x;
    }
    
    
  • 相关阅读:
    课上练习,判断大小。
    软件工程个人作业03。
    构建之法阅读笔记一。
    软件工程个人作业02。
    SSM常见面试题
    Bean的作用域和初始化时机(singleton&prototype)
    Spring中的AOP
    Spring核心概念和打印机案例
    MyBatis中的常用注解
    MyBatis中的延迟加载策略
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10948935.html
Copyright © 2011-2022 走看看