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

    题目链接:Click here

    Solution:

    注意到每个点的决策都是一定的,我们排序后通过双向链表来处理这个东西

    (A[i][j])表示从(i)出发,走了(2^j)轮时(A)开车的距离,(B[i][j])同理

    (f[i][j])则表示(2^j)轮后的位置,倍增优化dp即可

    Code:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=1e5+11;
    const int inf=3e9;
    int n,m,ans,Aa,Ab,h[N],id[N],pre[N],nxt[N],p[N];
    int f[N][20],A[N][20],B[N][20],mn[N],nmn[N];
    inline bool cmp(int a,int b){return h[a]<h[b];}
    int hdlt(int x,int y){return abs(h[x]-h[y]);}
    void prepare(){
        h[0]=h[n+1]=inf;
        for(int i=1;i<n;i++){
            int v=p[i];
            mn[i]=nxt[v];nmn[i]=pre[v];
            if(hdlt(i,id[nmn[i]])<hdlt(i,id[mn[i]])) swap(mn[i],nmn[i]);
            int nt=nxt[nxt[v]],pe=pre[pre[v]];
            if(hdlt(i,id[nmn[i]])>hdlt(i,id[nt])) nmn[i]=nt;
            if(hdlt(i,id[nmn[i]])>hdlt(i,id[pe])) nmn[i]=pe;
            if(hdlt(i,id[nmn[i]])==hdlt(i,id[nt])&&h[id[nt]]<h[id[nmn[i]]]) nmn[i]=nt;
            if(hdlt(i,id[nmn[i]])==hdlt(i,id[pe])&&h[id[pe]]<h[id[nmn[i]]]) nmn[i]=pe;
            nmn[i]=id[nmn[i]];mn[i]=id[mn[i]];
            if(hdlt(i,nmn[i])==hdlt(i,mn[i])&&h[nmn[i]]<h[mn[i]]) swap(mn[i],nmn[i]);
            nxt[pre[v]]=nxt[v];pre[nxt[v]]=pre[v];
        }
        for(int i=1;i<n;i++){
            f[i][0]=mn[nmn[i]];
            A[i][0]=hdlt(i,nmn[i]);
            B[i][0]=hdlt(nmn[i],mn[nmn[i]]);
        }
    }
    void trans(){
        for(int j=1;j<=19;j++)
            for(int i=1;i<=n;i++){
                f[i][j]=f[f[i][j-1]][j-1];
                A[i][j]=A[i][j-1]+A[f[i][j-1]][j-1];
                B[i][j]=B[i][j-1]+B[f[i][j-1]][j-1];
            }
    }
    void calc(int &a,int &b,int limit,int x){
        a=0,b=0;
        for(int i=19;i>=0;i--)
            if(f[x][i]&&A[x][i]+B[x][i]<=limit){
                a+=A[x][i],b+=B[x][i];
                limit-=A[x][i]+B[x][i];
                x=f[x][i];
            }
        if(hdlt(nmn[x],x)<=limit) a+=hdlt(nmn[x],x);
    }
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    signed main(){
        n=read();
        for(int i=1;i<=n;i++)
            h[i]=read(),id[i]=i;
        sort(id+1,id+n+1,cmp);
        for(int i=1;i<=n;i++)
            pre[i]=i-1,nxt[i]=i+1,p[id[i]]=i;
        prepare();trans();
        int Limit=read();m=read();
        for(int i=1;i<=n;i++){
            int a,b;calc(a,b,Limit,i);
            if(!ans||a*Ab<Aa*b)
                Aa=a,Ab=b,ans=i;
        }
        printf("%lld
    ",ans);
        for(int i=1;i<=m;i++){
            int x=read(),lim=read();
            int a,b;calc(a,b,lim,x);
            printf("%lld %lld
    ",a,b);
        }
        return 0;
    }
    
  • 相关阅读:
    两次动态输入和while的结合使用
    索引切片步长
    12.⽤户登陆(三次输错机会)且每次输错误时显示剩余错误次数(提示:使⽤字符串格式化)
    输出1-100的所以奇数或偶数
    求1-2+3-4+5 ... 99的所有数的和
    求1-100所有数的和
    三次登录机会
    while输入12345689
    while和格式化输出的复合使用
    44
  • 原文地址:https://www.cnblogs.com/NLDQY/p/11781067.html
Copyright © 2011-2022 走看看