Noip2012 开车旅行

Posted nldqy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于Noip2012 开车旅行的主要内容,如果未能解决你的问题,请参考以下文章

NOIP2012开车旅行

NOIP2012-开车旅行

Cogs1264. [NOIP2012] 开车旅行(70分 暴力)

Noip2012 开车旅行

NOIP2012开车旅行 倍增

noip2012开车旅行 [倍增]