傳送門
此題為複雜細節題,無法總結題意,所以給出原題:
小 \(\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。不過乙個是固定路徑長度的詢問,另乙個是給定起點和路徑長度的詢問。所以問題一和問題二是可以使用乙個函式解決的,而且對於乙個城市來說,在不考慮路程的情況下,路...