題目描述動態規劃+倍增。小 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位大臣排 成一排,國王站在隊伍的最前面。排好隊後,所有的大臣都會獲得國王獎賞的若干金幣,每 位大臣獲得...