luogu p1081 開車旅行

2021-10-19 04:20:03 字數 4160 閱讀 9486

傳送門

此題為複雜細節題,無法總結題意,所以給出原題:

小 \(\text\) 和小 \(\text\) 決定利用假期外出旅行,他們將想去的城市從 $1 $ 到 \(n\) 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 \(i\) 的海拔高度為\(h_i\),城市 \(i\) 和城市 \(j\) 之間的距離 \(d_\) 恰好是這兩個城市海拔高度之差的絕對值,即 \(d_=|h_i-h_j|\)。

旅行過程中,小 \(\text\) 和小 \(\text\) 輪流開車,第一天小 \(\text\) 開車,之後每天輪換一次。他們計畫選擇乙個城市 \(s\) 作為起點,一直向東行駛,並且最多行駛 \(x\) 公里就結束旅行。

小 \(\text\) 和小 \(\text\) 的駕駛風格不同,小 \(\text\) 總是沿著前進方向選擇乙個最近的城市作為目的地,而小 \(\text\) 總是沿著前進方向選擇第二近的城市作為目的地(注意:本題中如果當前城市到兩個城市的距離相同,則認為離海拔低的那個城市更近)。如果其中任何一人無法按照自己的原則選擇目的城市,或者到達目的地會使行駛的總距離超出 \(x\) 公里,他們就會結束旅行。

在啟程之前,小 \(\text\) 想知道兩個問題:

1、 對於乙個給定的 \(x=x_0\),從哪乙個城市出發,小 \(\text\) 開車行駛的路程總數與小 \(\text\) 行駛的路程總數的比值最小(如果小 \(\text\) 的行駛路程為 \(0\),此時的比值可視為無窮大,且兩個無窮大視為相等)。如果從多個城市出發,小 \(\text\) 開車行駛的路程總數與小 \(\text\) 行駛的路程總數的比值都最小,則輸出海拔最高的那個城市。

2、對任意給定的 \(x=x_i\) 和出發城市 \(s_i\),小 \(\text\) 開車行駛的路程總數以及小 \(\text b\) 行駛的路程總數。

首先考慮暴力做法。

預處理出四個陣列:a, b, disa, disb。

然後模擬行車過程即可。

**就不給了,懶得寫……

稍加思考便可知,預處理是 \(\mathcal(n ^ 2)\) 的。

然後再模擬行車過程,複雜度 \(\mathcal(nm)\)。

觀察資料範圍,暴力做法能得到 \(70 \mathtt\),分數非常可觀。

接下來就是正菜了,我們考慮在暴力的基礎上優化一下。

觀察到每次a和b的目標點在位置確定時就已經確定了,因此考慮倍增

distota[i][j] 表示汽車從i,被a和b輪流分別開了 1 << j 次後 a 的總路程

distotb[i][j] 表示汽車從i,被a和b輪流分別開了 1 << j 次後 b 的總路程

curpos[i][j] 表示汽車從i,被a和b輪流分別開了 1 << j 次後汽車的位置

先考慮 \(j=0\) 的情況:

for (int i = 1; i <= n; ++i)
這個還是很好理解的吧!

再來看看 \(j \ge 1\) 的情況:

for (int j = 1; j <= maxlogn - 5; ++j)

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

}

那麼倍增我們就優化完了,乙個 \(n\) 掉成了 \(\log n\)。但是這還遠遠不夠。

disa和disb的處理仍然是平方級別的。怎麼辦呢?我們使用雙向鍊錶來把這裡的預處理降低成 \(\mathcal(n)\) 級別。

首先,我們把這 \(n\) 個城市按照高度排序。(好吧,這已經 \(n \log n\) 了)

排序後,那麼乙個城市 \(i\) 的最小距離點和次小距離點,一定就在 \(i-2\), \(i-1\), \(i+1\), \(i+2\) 這四個位置上

那麼第乙個找點的顯然就是一號城市。然後你就會驚奇的發現,一號城市就是最西邊了,也就是說找到的任何城市都在一號城市東邊。這大大方便我們直接計算disa和disb的值。

找到之後,炸了一號城市,開始處理二號城市。嗯因為一號城市已經被炸了,同樣所有城市都在二號城市東邊,太方便啦!

處理完乙個炸乙個,直到最後炸沒了,整個disa和disb就求解完畢了。

至於為什麼用雙向鍊錶嘛,這是因為炸城市需要鍊錶維護,然後我們又需要找乙個城市的前驅和後繼,嗯,妥妥雙向鍊錶。

整體就是 \(\mathcal(n\log n)\) 這個級別的,顯然這個演算法可以通過此題。

那就上**吧!

/*

* @author: crab-in-the-northeast

* @date: 2020-11-20 23:36:45

* @last modified by: crab-in-the-northeast

* @last modified time: 2020-11-21 01:00:02

*/#include const int maxn = 100005;

const int maxlogn = 25;

const double eps = 0.0000001;

inline long long read()

while (ch >= '0' && ch <= '9')

if (f)

return x;

return ~(x - 1);

}int n;

long long a[maxn], b[maxn], disa[maxn], disb[maxn], distota[maxn][maxlogn], distotb[maxn][maxlogn], curpos[maxn][maxlogn];

struct building

}a[maxn];

int p[maxn];

inline void upddis(int spos, int s, int t) else if (disa[spos] == 0 || disa[spos] > dis || (disa[spos] == dis && a[t] < a[p[a[spos]]]))

return ;

}int main()

std :: sort(a + 1, a + 1 + n);

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

// solve disa, disb on

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

//puts("fff");

// solve distota, distotb, onlogn

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

for (int j = 1; j <= maxlogn - 5; ++j)

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

}// solve part1 nlogn

long long x0 = read(), ans = 0;

double minrat = int_max;

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

}if (disa[pos] <= tmpx)

ansa += disa[pos];

if (ansa == 0)

continue;

if (ans == 0 || minrat - 1.0 * ansa / ansb > eps || (fabs(minrat - 1.0 * ansa / ansb) <= eps && a[p[ans]] < a[p[i]]))

}std :: printf("%lld\n", ans);

// solve part2 mlogn

int m = read();

while (m--)

}if (disa[s] <= x)

ansa += disa[s];

std :: printf("%lld %lld\n", ansa, ansb);

}return 0;

}

如果對於乙個點,選擇具有唯一性(或者說跳到**的選擇只和位置有關),那麼就可以考慮倍增優化

附乙個白話倍增(經 典 作 品)

luogu p1081 開車旅行

傳送門此題為複雜細節題,無法總結題意,所以給出原題 小 text 和小 text 決定利用假期外出旅行,他們將想去的城市從 1 到 n 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i 的海拔高度為 h i 城市 i 和城市 j 之間的距離 d 恰好是這兩個城...

LG1081 開車旅行

城市 i 的海拔高度為 h i 各不相同 定義距離為海拔差的絕對值 小 a 和小 b 輪流開車。從 s 起,一直向東行駛。小 a 會選擇第二近的城市作為目的地。小 b 選擇乙個最近的城市作為目的地。如果當前城市到兩個城市的距離相同,則認為離海拔低的那個城市更近 如果無法再開了,或者到達目的地會使行駛...

P1081 開車旅行

p1081 開車旅行 排序優化 倍增 其實這道題一開始是一點也沒有頭緒,知道有高人指點了一下。說並不需要拘束於出發點和路徑長度,也就是問題1.2。不過乙個是固定路徑長度的詢問,另乙個是給定起點和路徑長度的詢問。所以問題一和問題二是可以使用乙個函式解決的,而且對於乙個城市來說,在不考慮路程的情況下,路...