NOIP2012開車旅行 倍增

2022-02-27 19:20:18 字數 3183 閱讀 6872

小 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 行駛的里程總數。

42 3 1 434

1 32 3

3 34 3

11 1

2 00 0

0 0對於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 互不相同。

以前沒a的一道題,今天補上

觀察題意可以看出,每次開車並沒有什麼決策,如果可以開,那麼目的地是確定的

那麼可以預處理倍增,這樣就可以\(o(nlogn)\)解決第乙個問,\(o(mlogn)\)解決第二個問

至於預處理,如何找出之後最近的和次近的,可以用平衡樹,但常數略大

考慮直接排序,那麼每個點最近的點一定在其左右兩格以內,拿出來比較一下就好

但從左到右訪問,訪問過的點不能作為之後的點的目的地【即只能向右開】,訪問完刪掉就好了,用雙向鍊錶實現

**略醜

#include#include#include#include#include#define ll long long int

#define rep(i,n) for (int i = 1; i <= (n); i++)

#define redge(u) for (int k = h[u]; k; k = ed[k].nxt)

using namespace std;

const int maxn = 100005,maxm = 100005,inf = 0x7fffffff;

const ll inf = 10000000000000000ll;

inline int read()

while (c >= 48 && c <= 57)

return out * flag;

}int n,m,h[maxn],nxt[2][maxn],to[maxn][20];

int id[maxn],ls[maxn],rs[maxn],temp[10],cnt;

ll cost[2][maxn][20];

inline bool cmp(const int& a,const int& b)

void init()

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

else if (d < nmin)

} nxt[0][i] = a;

nxt[1][i] = b;

if (ls[i]) rs[ls[i]] = rs[i];

if (rs[i]) ls[rs[i]] = ls[i];

} for (int i = 1; i <= n; i++)else cost[0][i][1] = cost[1][i][1] = inf;

} for (int t = 2; t <= 18; t++)else cost[0][i][t] = cost[1][i][t] = inf;

} }}void solve1()

if (nxt[0][now] && abs(h[nxt[0][now]] - h[now]) <= d)

ca += abs(h[nxt[0][now]] - h[now]);

if (!u || (cb == 0 && mb == 0 && h[i] > h[u]) || (mb == 0 && cb != 0) || (cb != 0 && (ca / cb < ma / mb || (fabs(ca / cb - ma / mb) < 1e-9 && h[i] > h[u]))))

u = i,ma = ca,mb = cb;

} printf("%d\n",u);

}void solve2()

} if (nxt[0][now] && fabs(h[nxt[0][now]] - h[now]) <= x)

ca += (int)fabs(h[nxt[0][now]] - h[now]);

printf("%d %d\n",ca,cb); }}

int main()

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...

NOIP2012 開車旅行 SET 倍增

啊,看到題 字好多。然後就直接開始碼暴力模擬了,覺得可以預處理一下每個點可以到達的最近點和次近點,這樣大概就有50分了 然而實際有70分。我忽略了只能往後走這一點帶來的便利,於是每一次都要找一次最近點 次近點 果然弱啊 暴力的過程寫的蠻。第一次只騙到15分 後來發現了bug調到35.就開始在精度這裡...