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\n",ans);
for(int i=1;i<=m;i++){
int x=read(),lim=read();
int a,b;calc(a,b,lim,x);
printf("%lld %lld\n",a,b);
}
return 0;
}