題解 P1081 【開車旅行】

A\text{A} 和小 B\text{B} 決定利用假期外出旅行,他們將想去的城市從 $1 $ 到 nn 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 ii 的海拔高度爲hih_i,城市 ii 和城市 jj 之間的距離 di,jd_{i,j} 恰好是這兩個城市海拔高度之差的絕對值,即 di,j=hihjd_{i,j}=|h_i-h_j|

旅行過程中,小 A\text{A} 和小 B\text{B} 輪流開車,第一天小 A\text{A} 開車,之後每天輪換一次。他們計劃選擇一個城市 ss 作爲起點,一直向東行駛,並且最多行駛 xx 公里就結束旅行。

A\text{A} 和小 B\text{B} 的駕駛風格不同,小 B\text{B} 總是沿着前進方向選擇一個最近的城市作爲目的地,而小 A\text{A} 總是沿着前進方向選擇第二近的城市作爲目的地(注意:本題中如果當前城市到兩個城市的距離相同,則認爲離海拔低的那個城市更近)。如果其中任何一人無法按照自己的原則選擇目的城市,或者到達目的地會使行駛的總距離超出 xx 公里,他們就會結束旅行。

在啓程之前,小 A\text{A} 想知道兩個問題:

  1. 對於一個給定的 x=x0x=x_0,從哪一個城市出發,小 A\text{A} 開車行駛的路程總數與小 B\text{B} 行駛的路程總數的比值最小(如果小 B\text{B} 的行駛路程爲 00,此時的比值可視爲無窮大,且兩個無窮大視爲相等)。如果從多個城市出發,小 A\text{A} 開車行駛的路程總數與小 B\text{B} 行駛的路程總數的比值都最小,則輸出海拔最高的那個城市。

  2. 對任意給定的 x=xix=x_i 和出發城市 sis_i,小 A\text{A} 開車行駛的路程總數以及小 B\text B 行駛
    的路程總數。

假設這個並非是必須向東行駛。

我們可以對 hh 數組進行排序。

則排好序的第 xx 個城市,第 11 近的城市和第 22 進的城市,一定在 x2,x1,x+1,x+2x-2,x-1,x+1,x+2 這些城市當中。

那麼向東行駛怎麼處理呢?

我們可以用這樣一個思想:

首先,想讓第 xx 個城市沒有向東行的限制,可以直接把 1x11 \sim x-1x1x-1 個城市刪掉

這樣就可以解除向東行的限制。

我們可以試着用一個鏈表,來模擬這個東西。

priority_queue<pair<int,pair<int,int> > >q;
read(n);
for(int i=1;i<=n;i++){
	read(m[i].h);
	m[i].id=i;
}sort(m+1,m+n+1,cmp);
for(int i=1;i<=n;i++){
	id[m[i].id]=i;
	pre[i]=i-1;lat[i]=i+1;
}
for(int i=1;i<=n;i++){
	while(q.size())q.pop();
	int x=id[i];
	int p1=pre[x],p2=pre[pre[x]],l1=lat[x],l2=lat[lat[x]];
	bool pb1=true,pb2=true,lb1=true,lb2=true;
	if(p1<=0)pb1=false;
	else if(p2<=0)pb2=false;
	if(l1>n)lb1=false;
	else if(l2>n)lb2=false;
	if(pb1){
		q.push(make_pair(-abs(m[x].h-m[p1].h),make_pair(-m[p1].h,p1)));
		if(pb2)q.push(make_pair(-abs(m[x].h-m[p2].h),make_pair(-m[p2].h,p2)));
	}
	if(lb1){
		q.push(make_pair(-abs(m[x].h-m[l1].h),make_pair(-m[l1].h,l1)));
		if(lb2)q.push(make_pair(-abs(m[x].h-m[l2].h),make_pair(-m[l2].h,l2)));
	}
	if(q.size())fi[i]=m[q.top().second.second].id;
	if(q.size())q.pop();
	if(q.size())se[i]=m[q.top().second.second].id;
	lat[p1]=lat[x];pre[l1]=pre[x];
}

我這裏是用一個堆,pushpush4\leq 4 個可能的數,然後搞。

之後就直接倍增,這裏就不詳細講了

#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &FF){
	T RR=1;FF=0;char CH=getchar();
	for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
	for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
	FF*=RR;
}
const int MAXN=1e5+10;
struct node{
	int h,id;
}m[MAXN];
int n,id[MAXN],pre[MAXN],lat[MAXN],fi[MAXN],se[MAXN],f[MAXN][25],a[MAXN][25],b[MAXN][25],A,B;
double Min=10000000000;
priority_queue<pair<int,pair<int,int> > >q;
bool cmp(node a,node b){
	return a.h<b.h;
}
void work(int x,int x1){
	A=0;B=0;
	for(int j=19;j>=0;j--)
		if(f[x1][j]&&(A+B+a[x1][j]+b[x1][j])<=x){
			A+=a[x1][j];
			B+=b[x1][j];
			x1=f[x1][j];
		}
	if(se[x1]&&A+B+a[x1][0]<=x)A+=a[x1][0];
}
int main(){
	read(n);
	for(int i=1;i<=n;i++){
		read(m[i].h);
		m[i].id=i;
	}sort(m+1,m+n+1,cmp);
	for(int i=1;i<=n;i++){
		id[m[i].id]=i;
		pre[i]=i-1;lat[i]=i+1;
	}
	for(int i=1;i<=n;i++){
		while(q.size())q.pop();
		int x=id[i];
		int p1=pre[x],p2=pre[pre[x]],l1=lat[x],l2=lat[lat[x]];
		bool pb1=true,pb2=true,lb1=true,lb2=true;
		if(p1<=0)pb1=false;
		else if(p2<=0)pb2=false;
		if(l1>n)lb1=false;
		else if(l2>n)lb2=false;
		if(pb1){
			q.push(make_pair(-abs(m[x].h-m[p1].h),make_pair(-m[p1].h,p1)));
			if(pb2)q.push(make_pair(-abs(m[x].h-m[p2].h),make_pair(-m[p2].h,p2)));
		}
		if(lb1){
			q.push(make_pair(-abs(m[x].h-m[l1].h),make_pair(-m[l1].h,l1)));
			if(lb2)q.push(make_pair(-abs(m[x].h-m[l2].h),make_pair(-m[l2].h,l2)));
		}
		if(q.size())fi[i]=m[q.top().second.second].id;
		if(q.size())q.pop();
		if(q.size())se[i]=m[q.top().second.second].id;
		lat[p1]=lat[x];pre[l1]=pre[x];
	}
	for(int i=1;i<=n;i++){
		f[i][0]=fi[se[i]];
		a[i][0]=abs(m[id[i]].h-m[id[se[i]]].h);
		b[i][0]=abs(m[id[fi[se[i]]]].h-m[id[se[i]]].h);
	}
	for(int j=1;j<=20;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];
		}
	int x,ans;read(x);
	for(int i=1;i<=n;i++){
		work(x,i);
		if(B&&1.0*A/B<Min){
			Min=1.0*A/B;
			ans=i;
		}
	}cout<<ans<<endl;
	int T;for(read(T);T--;){
		int j,x;read(j);read(x);
		work(x,j);
		printf("%d %d\n",A,B);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章