NOIP2012DAY1T3【開車旅行】

Description

小A和小B決定利用假期外出旅行,他們將想去的城市從1到N編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市i 的海拔高度爲Hi,城市i 和城市j 之間的距離d[i,j]恰好是這兩個城市海拔高度之差的絕對值,即d[i,j] = |Hi - Hj|。 
旅行過程中,小A和小B輪流開車,第一天小A開車,之後每天輪換一次。他們計劃選擇一個城市S作爲起點,一直向東行駛,並且最多行駛X公里就結束旅行。小A和小B的駕駛風格不同,小B總是沿着前進方向選擇一個最近的城市作爲目的地,而小A總是沿着前進方向選擇第二近的城市作爲目的地(注意:本題中如果當前城市到兩個城市的距離相同,則認爲離海拔低的那個城市更近)。如果其中任何一人無法按照自己的原則選擇目的城市,或者到達目的地會使行駛的總距離超出X公里,他們就會結束旅行。 
在啓程之前,小A想知道兩個問題:

  1. 對於一個給定的X=X0,從哪一個城市出發,小A開車行駛的路程總數與小B行駛的路程總數的比值最小(如果小B的行駛路程爲0,此時的比值可視爲無窮大,且兩個無窮大視爲相等)。如果從多個城市出發,小A開車行駛的路程總數與小B行駛的路程總數的比值都最小,則輸出海拔最高的那個城市。
  2. 對任意給定的X=Xi 和出發城市Si,小A開車行駛的路程總數以及小B行駛的路程總數。

Input Format

第一行包含一個整數N,表示城市的數目。 
第二行有N個整數,每兩個整數之間用一個空格隔開,依次表示城市1到城市N的海拔高度,即H1,H2,……,Hn,且每個Hi 都是不同的。 
第三行包含一個整數X0。 
第四行爲一個整數M,表示給定M組Si和Xi。 
接下來的M行,每行包含2個整數Si 和Xi,表示從城市Si 出發,最多行駛Xi 公里。

Output Format

輸出共M+1行。 
第一行包含一個整數S0,表示對於給定的X0,從編號爲S0的城市出發,小A開車行駛 的路程總數與小B行駛的路程總數的比值最小。 
接下來的M行,每行包含2個整數,之間用一個空格隔開,依次表示在給定的Si 和Xi 下小A行駛的里程總數和小B行駛的里程總數。

Sample Input

樣例1
4 
2 3 1 4 
3 
4 
1 3 
2 3 
3 3 
4 3
樣例2
10 
4 5 6 1 2 3 7 8 9 10 
7 
10 
1 7 
2 7 
3 7 
4 7 
5 7 
6 7 
7 7 
8 7 
9 7 
10 7  

Sample Output

樣例1
1 
1 1 
2 0 
0 0 
0 0
樣例2
2 
3 2 
2 4 
2 1 
2 4 
5 1 
5 1 
2 1 
2 0 
0 0 
0 0 

Hint

對於30%的數據,有1≤N≤20,1≤M≤20; 
對於40%的數據,有1≤N≤100,1≤M≤100; 
對於50%的數據,有1≤N≤100,1≤M≤1,000; 
對於70%的數據,有1≤N≤1,000,1≤M≤10,000; 

對於100%的數據,有1≤N≤100,000,1≤M≤10,000,-1,000,000,000≤Hi≤1,000,000,000,0≤X0≤1,000,000,000,1≤Si≤N,0≤Xi≤1,000,000,000,數據保證Hi 互不相同。

【題解】

倍增 雙向鏈表

首先一定要預處理在A和B在每個點上出發到達的點(可以用各種數據結構處理),推薦比較高效的雙向鏈表(與noip2016初賽完善程序第一題一樣)

然後用倍增的做法f[i][j]記錄從i點出發AB輪換2^j輪後到達的地點(一輪是AB都開了一次車

g[i][j][0]i到f[i][j]中A走的路程 g[i][j][1]記錄B的路程

對於第一問枚舉每一個起點倍增到不能走 最後比較一下就行了

第二問就直接從給定起點做倍增就行

詳見代碼

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>
#include <map>
using namespace std;
long long g[100005][22][2],a,b,l,x;
double MIN,d;
int f[100005][22],get[100005][2],rank[100005],lef[100005],rig[100005];
struct info
  {
  	long long h;
  	int num;
  }city[100005],t[10];
int i,j,k,m,n,ans,s;
bool cmp(info x,info y) {return x.h<y.h;}
bool cmp1(info x,info y) {return (x.h<y.h || (x.h==y.h&&city[rank[x.num]].h<city[rank[y.num]].h));}
int main()
  {
  	scanf("%d",&n);
  	for (i=1;i<=n;i++) scanf("%lld",&city[i].h),city[i].num=i;
    sort(city+1,city+n+1,cmp);
    for (i=1;i<=n;i++) rank[city[i].num]=i;
    for (i=1;i<=n;i++) lef[i]=i-1,rig[i]=i+1;
    city[0].h=city[n+1].h=1e9;
    for (i=1;i<=n;i++)
      {
      	k=0;
      	if (lef[rank[i]]!=0) t[++k]={abs(city[lef[rank[i]]].h-city[rank[i]].h),city[lef[rank[i]]].num};
      	if (rig[rank[i]]!=n+1) t[++k]={abs(city[rig[rank[i]]].h-city[rank[i]].h),city[rig[rank[i]]].num};
      	if (lef[lef[rank[i]]]!=0) t[++k]={abs(city[lef[lef[rank[i]]]].h-city[rank[i]].h),city[lef[lef[rank[i]]]].num};
      	if (rig[rig[rank[i]]]!=n+1) t[++k]={abs(city[rig[rig[rank[i]]]].h-city[rank[i]].h),city[rig[rig[rank[i]]]].num};
        sort(t+1,t+k+1,cmp1);
        rig[lef[rank[i]]]=rig[rank[i]];
		lef[rig[rank[i]]]=lef[rank[i]];
		if (k>0) get[i][1]=t[1].num;
		if (k>1) get[i][0]=t[2].num;
	  }
	for (i=1;i<=n;i++)
	  {
	  	j=get[i][0];k=get[j][1];
	  	if (k!=0) f[i][0]=k;else f[i][0]=i;
		if (j!=0) g[i][0][0]=abs(city[rank[i]].h-city[rank[j]].h);else g[i][0][0]=1e15;
	    if (j!=0&&k!=0) g[i][0][1]=abs(city[rank[j]].h-city[rank[k]].h);else g[i][0][1]=1e15;
	  }
	for (i=1;i<=20;i++)
	  for (j=1;j<=n;j++)
	    {
	       f[j][i]=f[f[j][i-1]][i-1];
		   if (g[j][i-1][0]==1e15||g[f[j][i-1]][i-1][0]==1e15) g[j][i][0]=1e15;
		   else g[j][i][0]=g[j][i-1][0]+g[f[j][i-1]][i-1][0];
		   if (g[j][i-1][1]==1e15||g[f[j][i-1]][i-1][1]==1e15) g[j][i][1]=1e15;
		   else g[j][i][1]=g[j][i-1][1]+g[f[j][i-1]][i-1][1];
		} 
	scanf("%d",&x);MIN=1e16;
	for (i=1;i<=n;i++)
	  {
	  	l=0;k=i;a=0;b=0;
	  	for (;l+g[k][0][0]+g[k][0][1]<=x;)
	  	  {
	  	  	for (j=0;l+g[k][j][0]+g[k][j][1]<=x;j++);j--;
	  	  	l+=g[k][j][0]+g[k][j][1];
			a+=g[k][j][0];b+=g[k][j][1];
			k=f[k][j];
		  }
		if (l+g[k][0][0]<=x) a+=g[k][0][0];
		if (b==0) d=1e15;else d=a/1.0/b;
		if (d<MIN) ans=i,MIN=d; 
	  }
	printf("%d\n",ans);
	for (scanf("%d",&m);m;m--)  
	  {
	  	scanf("%d%lld",&s,&x);
	  	l=0;k=s;a=0;b=0;
	  	for (;l+g[k][0][0]+g[k][0][1]<=x;)
	  	  {
	  	  	for (j=0;l+g[k][j][0]+g[k][j][1]<=x;j++);j--;
	  	  	l+=g[k][j][0]+g[k][j][1];
			a+=g[k][j][0];b+=g[k][j][1];
			k=f[k][j];
		  }
		if (l+g[k][0][0]<=x) a+=g[k][0][0];
	    printf("%lld %lld\n",a,b);  
	  }
  }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章