NOIP2012开车旅行 【倍增】
題目
小 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 行駛的里程總數。
輸入樣例
4
2 3 1 4
3
4
1 3
2 3
3 3
4 3
輸出樣例
1
1 1
2 0
0 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<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #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(){int out = 0,flag = 1; char c = getchar();while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}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){return h[a] < h[b];} void init(){sort(id + 1,id + 1 + n,cmp);for (int i = 1; i <= n; i++){if (i != 1) ls[id[i]] = id[i - 1];if (i != n) rs[id[i]] = id[i + 1];}for (int i = 1; i <= n; i++){cnt = 0;int j = ls[i],gmin = INF,nmin = INF,a = 0,b = 0;if (ls[j]) temp[++cnt] = ls[j],temp[++cnt] = j;else if (j) temp[++cnt] = j;j = rs[i];if (rs[j]) temp[++cnt] = j,temp[++cnt] = rs[j];else if (j) temp[++cnt] = j;for (j = 1; j <= cnt; j++){int d = abs(h[i] - h[temp[j]]);if (d < gmin){nmin = gmin; gmin = d;a = b; b = temp[j];}else if (d < nmin){nmin = d; a = temp[j];}}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++){if (nxt[1][nxt[0][i]]){to[i][1] = nxt[1][nxt[0][i]];cost[0][i][1] = abs(h[nxt[0][i]] - h[i]);cost[1][i][1] = abs(h[nxt[1][nxt[0][i]]] - h[nxt[0][i]]);}else cost[0][i][1] = cost[1][i][1] = inf;}for (int t = 2; t <= 18; t++){for (int i = 1; i <= n; i++){if (to[to[i][t - 1]][t - 1]){to[i][t] = to[to[i][t - 1]][t - 1];cost[0][i][t] = cost[0][i][t - 1] + cost[0][to[i][t - 1]][t - 1];cost[1][i][t] = cost[1][i][t - 1] + cost[1][to[i][t - 1]][t - 1];}else cost[0][i][t] = cost[1][i][t] = inf;}} } void solve1(){int X = read(),u = 0,d,now;double ca,cb,ma,mb;for (int i = 1; i <= n; i++){d = X; ca = 0; cb = 0; now = i;for (int j = 18; j; j--)if (to[now][j] && cost[0][now][j] + cost[1][now][j] <= d){d -= cost[0][now][j] + cost[1][now][j];ca += cost[0][now][j];cb += cost[1][now][j];now = to[now][j];}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(){m = read();int x,now,ca,cb;while (m--){now = read(); x = read(); ca = cb = 0;for (int i = 18; i; i--){if (to[now][i] && cost[0][now][i] + cost[1][now][i] <= x){x -= cost[0][now][i] + cost[1][now][i];ca += cost[0][now][i];cb += cost[1][now][i];now = to[now][i];}}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(){n = read();for (int i = 1; i <= n; i++) h[i] = read(),id[i] = i;init();solve1();solve2();return 0; }轉載于:https://www.cnblogs.com/Mychael/p/8455020.html
總結
以上是生活随笔為你收集整理的NOIP2012开车旅行 【倍增】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV3计算机视觉+Python(
- 下一篇: dp和px