NOIP2012 洛谷1081 開車旅行

2021-07-15 03:51:24 字數 3840 閱讀 7039

題目描述

小 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 行駛的路程總數的比

值都最小,則輸出海拔最高的那個城市。

對任意給定的 x=xi和出發城市 si,小 a 開車行駛的路程總數以及小 b 行駛的路程
總數。 輸入輸出格式 輸入格式:

第一行包含乙個整數 n,表示城市的數目。

第二行有 n 個整數,每兩個整數之間用乙個空格隔開,依次表示城市 1 到城市 n 的海

拔高度,即 h1,h2,……,hn,且每個 hi都是不同的。

第三行包含乙個整數 x0。

第四行為乙個整數 m,表示給定 m 組 si和 xi。

接下來的 m 行,每行包含 2 個整數 si和 xi,表示從城市 si出發,最多行駛 xi公里。

輸出格式:

輸出共 m+1 行。

第一行包含乙個整數 s0,表示對於給定的 x0,從編號為 s0的城市出發,小 a 開車行駛

的路程總數與小 b 行駛的路程總數的比值最小。

接下來的 m 行,每行包含 2 個整數,之間用乙個空格隔開,依次表示在給定的 si和

xi下小 a 行駛的里程總數和小 b 行駛的里程總數。

動態規劃+倍增。

dis[i][j][k][l]表示從i點出發,走2^j步,k先走,l的路程長度。

求出這個以後,就可用倍增求出某一點出發路程總長度不超過某乙個值,兩個人分別走的路程長度。

這樣對於第二問,直接求。對於第一問,列舉起點求。

因為每次計算複雜度是o(logn),所以計算階段的總複雜度為o(nlogn+mlogn)。

接下來考慮如何求dis陣列。

不難寫出轉移方程dis[i][j][k][l]=dis[i][j-1][k][l]+dis[des[i][j-1][k]][j-1][k][l]。

其中des[i][j][k]表示從i出發,走2^j步,k先開,最後的終點。

邊界條件就是j=0,直接根據des計算。

這一步的複雜度為o(nlogn)。

接下來考慮如何求des陣列。

同理,不難寫出方程des[i][j][k]=des[des[i][j-1][k]][j-1][k]。

但是有兩點需要注意。

1.j=1時特殊考慮,方程變為des[i][1][k]=des[des[i][0][j]][0][k^1]。

2.邊界條件,即如何求des[i][0][j]。

建立一棵平衡樹【或者直接用set】,從右向左掃瞄,掃瞄到某乙個點時,當前set裡的就是該點右邊的點。用lower_bound()即可求出最近點和次近點。然後把該點插入set中。

平衡樹複雜度o(nlogn),求des同樣o(nlogn)。

綜上所述,總的時間複雜度為o((m+n)logn)。

實現時注意的細節:

1.set裡可以預先插入無窮大和無窮小,避免各種re。

2.倍增求dis和des的時候,2的冪j迴圈要放在最外面。

#include

#include

#include

#include

#include

#include

using

namespace

std;

const

long

long oo=100000023333333;

long

long des[100010][20][2],dis[100010][20][2][2],to[100010][2],lim,n;

struct city

void cal(int s,long

long l,long

long &ansa,long

long &ansb)

else

p--;

}int main()

setpl;

tem.num=0;

tem.hei=oo;

pl.insert(tem);

tem.hei=-oo;

pl.insert(tem);

tem.hei=oo+1;

pl.insert(tem);

tem.hei=-oo-1;

pl.insert(tem);

for (i=n;i>=1;i--)

else

pl.insert(dat[i]);

}for (i=1;i<=n;i++)

for (j=0;j<=1;j++)

des[i][0][j]=to[i][j];

for (i=1;i<=n;i++)

for (j=0;j<=1;j++)

des[i][1][j]=des[des[i][0][j]][0][j^1];

for (j=2;j<=lim;j++)

for (i=1;i<=n;i++)

for (k=0;k<=1;k++)

des[i][j][k]=des[des[i][j-1][k]][j-1][k];

for (i=1;i<=n;i++)

for (j=0;j<=1;j++)

dis[i][0][j][j]=abs(dat[i].hei-dat[des[i][0][j]].hei);

for (i=1;i<=n;i++)

for (j=0;j<=1;j++)

for (k=0;k<=1;k++)

if (j==k)

dis[i][1][j][j]=dis[i][0][j][j];

else

dis[i][1][j][k]=dis[des[i][0][j]][0][k][k];

for (j=2;j<=lim;j++)

for (i=1;i<=n;i++)

for (k=0;k<=1;k++)

for (l=0;l<=1;l++)

dis[i][j][k][l]=dis[i][j-1][k][l]+dis[des[i][j-1][k]][j-1][k][l];

scanf("%lld",&len);

cal(1,len,ansa,ansb);

ans=1;

for (i=2;i<=n;i++)

}else}}

printf("%lld\n",ans);

scanf("%lld",&m);

for (i=1;i<=m;i++)

}

NOIP2012 洛谷P1084 疫情控制

description h 國有 n 個城市,這 n 個城市用 n 1 條雙向道路相互連通構成一棵樹,1 號城市是首都,也是樹中的根節點。h 國的首都爆發了一種危害性極高的傳染病。當局為了控制疫情,不讓疫情擴散到邊境城市 葉子節點所表示的城市 決定動用軍隊在一些城市建立檢查點,使得從首都到邊境城市的...

NOIP2012 簡要題解

day1 p1vigenere密碼 直接根據規律模擬即可 include include include include include using namespace std const int maxn 2000 char s maxn t maxn int calc char c int ma...

noip2012國王遊戲

game.cpp c pas 問題描述 恰逢 h 國國慶,國王邀請 n 位大臣來玩乙個有獎遊戲。首先,他讓每個大臣在左 右 手上面分別寫下乙個整數,國王自己也在左 右手上各寫乙個整數。然後,讓這 n位大臣排 成一排,國王站在隊伍的最前面。排好隊後,所有的大臣都會獲得國王獎賞的若干金幣,每 位大臣獲得...