Noip2012 開車旅行 (倍增DP,難)

2022-01-10 05:33:13 字數 2967 閱讀 9879

小 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 想知道兩個問題:

對於乙個給定的 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 行駛的里程總數。

對於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≤100,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 互不相同。

思路參考於 巨佬youngneal 和 演算法書:演算法競賽高階指南

這題的首先乙個難點就是預處理。\(ga(i)\) 和 \(gb(i)\) 記為小a和小b從城市 \(i\) 出發按前進方向行駛到的下乙個城市。

首先預處理出 a 和 b 每個人從乙個城市出發的目標是哪個城市。可以用平衡樹找乙個點的前驅和後繼,或者雙向鍊錶。而 \(ga(i)\) 就等於 \(i + 1\) ~ \(n\) 中 使 \(dist(i,j)\) 取到最小值的城市 。\(gb(i)\) 就是取到次最小值的城市 \(j\) 。我當然選擇了最偷懶的 set。(upd:這裡如果用 set 的話有可能迭代器一直加或者減導致越界,又懶得判斷,索性用了 multiset)

本題有三個關鍵條件:所在城市、已行駛的天數、a和b各行駛的路徑長度。所以設\(f[i,j,k(0/1)]\) 表示從城市j出發,兩人共行駛\(2^i\) 天,\(k\) 先開車,最終會到達的城市。k = 0 代表小a先開車,k = 1代表小b先開車。

初值 \(f[0,j,0] = ga(j),f[0,j,1] = gb(j)\)。

當 \(i = 1\) 時,因為\(2^0\) 為奇數,所以兩人從\(j\) 出發開 \(2^1\) 天到達的城市,等於 \(k\) 先開 \(2^0\) 天,另一人 \(1 - k\) 再開 \(2^0\) 天到達的城市。

\[f[1,j,k] = f[0,f[0,j,k],1 - k]

\]當 \(i > 1\) 時,因為 \(2^\) 是偶數,所以前後兩半路程都輪到 k 先開車。

\[f[i,j,k] = f[i - 1,f[i -1 ,j,j],k]

\]

#include#define pii pairusing namespace std;

typedef pairpii;

const int n = 100006, inf = 0x3f3f3f3f;

int n, m, h[n], x[n], s[n], ga[n], gb[n], w;

int f[18][n][2], da[18][n][2], db[18][n][2], la, lb;

multisetst;

multiset::iterator it, it1, it2, it3, it4;

void calc(int s, int x)

}int main()

else

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

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

for (int i = 2; i < w; i++)

for (int j = 1; j <= n; j++)

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

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

for (int i = 2; i < w; i++)

for (int j = 1; j <= n; j++)

calc(1, x[0]);

double ans1[2] = ;

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

} cout << ans1[0] << endl;

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

}

NOIP2012 開車旅行 (倍增)

小 a 和小 b 決定利用假期外出旅行,他們將想去的城市從 1 到 n 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i 的海拔高度為hi,城市 i 和城市 j 之間的距離 d i,j 恰好是這兩個城市海拔高度之差的絕對值,即d i,j hi hj 旅行過程中...

NOIP2012開車旅行 倍增

小 a 和小 b 決定利用假期外出旅行,他們將想去的城市從 1 到 n 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i 的海拔高度為hi,城市 i 和城市 j 之間的距離 d i,j 恰好是這兩個城市海拔高度之差的絕對值,即d i,j hi hj 旅行過程中...

noip2012 開車旅行 set 倍增

因為要快速查詢向後跳應該是哪乙個點,所以用set,迭代器左右晃一下查詢最接近的兩個元素 p選手是不是只能用平衡樹 然後用倍增記錄i節點跳2 j步後,a和b分別走的距離。具體的細節和統計答案也需要注意。include include include include include include de...