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

    题意

    城市\(i\)的海拔高度为\(H_i\)(各不相同)。定义距离为海拔差的绝对值
    \(A\)和小\(B\)轮流开车。从\(S\)起,一直向东行驶。
    \(A\)会选择第二近的城市作为目的地。小\(B\)选择一个最近的城市作为目的地。(如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果无法再开了,或者到达目的地会使行驶的总距离超出\(X\)公里,他们就会结束旅行。

    单次询问:给定\(X\),问从哪个城市出发,小\(A\)行的路程与小\(B\)行的路程的比值最小
    多次询问:给定\(S\)\(X\),问小\(A\)行的路程与小\(B\)行的路程
    \(1 \leq N \leq 10^5,1 \leq M \leq 10^5\)

    思路

    首先肯定要解决一个问题,小\(A\)和小\(B\)的目的地在哪里。
    先排序,然后从第一个城市开始,比较\(i-1,i-2,i+1,i+2\)处距离。
    很显然,由于是第一个点,这个时候找到的任何点一定在它东边。
    同样的,找完第一个点后将第一个点删除,那么第二个点自然成为了第一个点,依次下去,便在\(O(n)\)的复杂度内完成了预处理。

    接下来,就可以想到用倍增来解决。
    \(f[i][j]\)表示从\(j\)出发第\(2^i\)天到达的城市,发现除了\(i=0\)时是\(A\)在开其他都是\(B\)开,所以转移就很简单了\(f[i][j]=f[i-1][f[i-1][j]];\)
    那么求出了路径,距离只要减一减就好了。
    \(g[i][j][0]\)表示从\(j\)出发第\(2^i\)\(A\)开的,用\(g[i][j][1]\)表示从\(j\)出发第\(2^i\)\(B\)开的,转移:
    \(g[i][j][0]=g[i-1][j][0]+g[i-1][f[i-1][j]][0];\)
    \(g[i][j][1]=g[i-1][j][1]+g[i-1][f[i-1][j]][1];\)

    接下来的询问只要每次倍增凑距离就好了
    对于第一个询问枚举出发点再比较
    时间复杂度\(O((n+m)logn)\)

    #include <bits/stdc++.h>
    const int N=100005;
    double INF=1000000000;
    using std::sort;
    int a[N],b[N],Next[N],last[N],c[N],n,m,f[21][N],x,ans=0,s;
    long long h[N],suma,sumb,g[21][N][2];
    bool cmp(int x,int y){
        return h[x]<h[y];
    }
    int d(int x,int y){
        return abs(h[x]-h[y]);
    }
    void solve(int x,int s){
        for (int i=20;i>=0;i--)
            if (g[i][s][0]+g[i][s][1]<=1ll*x){
                x-=g[i][s][0]+g[i][s][1];
                suma+=g[i][s][0];
                sumb+=g[i][s][1];
                if (s==f[i][s]) return;
                s=f[i][s];
            }
    }
    int main(){
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%lld",&h[i]),c[i]=i;
        h[0]=-200000000000;
        sort(c+1,c+n+1,cmp);
        for (int i=1;i<=n;i++) last[c[i]]=c[i-1],Next[c[i]]=c[i+1];
        for (int i=1;i<=n;i++){
            int x1=last[i],x2=last[x1],x3=Next[i],x4=Next[x3];
            int dis1=abs(h[i]-h[x1]),dis2=abs(h[i]-h[x2]),dis3=abs(h[i]-h[x3]),dis4=abs(h[i]-h[x4]);
            if (dis1<dis3 ||(dis1==dis3 && h[x1]<h[x3])) b[i]=x1; else b[i]=x3;
            if (dis2<dis3 ||(dis2==dis3 && h[x2]<h[x3])) a[i]=x2;
            else if (dis4<dis1 ||(dis4==dis1 && h[x4]<h[x1])) a[i]=x4;
            else if (dis1<dis3 ||(dis1==dis3 && h[x1]<h[x3])) a[i]=x3;
            else a[i]=x1;
            if (a[i]==0) a[i]=i;
            if (b[i]==0) b[i]=i;
            last[Next[i]]=last[i],Next[last[i]]=Next[i];
        }
        for (int i=1;i<=n;i++){
            f[0][i]=a[i];if (a[i]!=i) f[1][i]=b[a[i]];else f[1][i]=i;
            g[0][i][0]=d(i,f[0][i]),g[1][i][0]=g[0][i][0];
            if (a[i]!=i)g[1][i][1]=d(a[i],b[a[i]]);
        }
        for (int i=2;i<=20;i++)
            for (int j=1;j<=n;j++){
                f[i][j]=f[i-1][f[i-1][j]];
                g[i][j][0]=g[i-1][j][0]+g[i-1][f[i-1][j]][0];
                g[i][j][1]=g[i-1][j][1]+g[i-1][f[i-1][j]][1];
            }
        scanf("%d",&x);
        double now=INF;
        for (int i=1;i<=n-2;i++){
            suma=0,sumb=0;
            solve(x,i);
            if (now==INF && sumb==0 && h[i]>h[ans]) ans=i;
            if (sumb==0) continue;
            if (suma*1.0/sumb<now ||(suma*1.0/sumb==now && h[i]>h[ans])){
                now=suma*1.0/sumb;
                ans=i;
            } 
        }
        printf("%d\n",ans);
        scanf("%d",&m);
        for (int i=1;i<=m;i++){
            scanf("%d%d",&s,&x);
            suma=0,sumb=0;
            solve(x,s);
            printf("%lld %lld\n",suma,sumb);
        }
    } 
    

    后记

    要注意\(h[0]\)的初始化,原来没仔细看数据结果爆了\(4\)

  • 相关阅读:
    防删没什么意思啊,直接写废你~
    绝大多数情况下,没有解决不了的问题,只有因为平时缺少练习而惧怕问题的复杂度,畏惧的心理让我们选择避让,采取并不那么好的方案去解决问题
    Java 模拟面试题
    Crossthread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on
    一步步从数据库备份恢复SharePoint Portal Server 2003
    【转】理解 JavaScript 闭包
    Just For Fun
    The database schema is too old to perform this operation in this SharePoint cluster. Please upgrade the database and...
    Hello World!
    使用filter筛选刚体碰撞
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/10625564.html
Copyright © 2011-2022 走看看