1. 程式人生 > >[NOIP2012]開車旅行

[NOIP2012]開車旅行

stream 思想 -i nod 開車 fin pri double 復雜

這道題的主要思想是倍增。其次的難點在於預處理,這裏使用鏈表來實現。

復雜度:$O(n log n)$

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cmath>
  6 
  7 using namespace std;
  8 
  9 #define re register
 10 #define LL long long
 11 #define
rep(i, x, y) for (register int i = x; i <= y; ++i) 12 #define repd(i, x, y) for (register int i = x; i >= y; --i) 13 #define maxx(a, b) a = max(a, b) 14 #define minn(a, b) a = min(a, b) 15 #define inf 1e17 16 17 inline LL read() { 18 LL w = 0, f = 1; char c = getchar(); 19
while (!isdigit(c)) f = c == - ? -1 : f, c = getchar(); 20 while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ 48), c = getchar(); 21 return w * f; 22 } 23 24 const int maxn = 1e5 + 5; 25 26 struct Dist { 27 LL A, B, to; 28 } f[20][maxn]; 29 30 struct
Node { 31 int id; 32 LL v; 33 } nd[maxn]; 34 35 int L[maxn], R[maxn]; 36 37 int n, m, jp1[maxn], jp2[maxn]; 38 LL H[maxn], X0; 39 40 int comp(int x, int a, int b) { 41 re LL va = abs(H[x] - H[a]), vb = abs(H[x] - H[b]); 42 if (va < vb) return a; 43 else if (va == vb) return H[a] < H[b] ? a : b; 44 else return b; 45 } 46 47 bool cmp1(Node a, Node b) { 48 return a.v < b.v; 49 } 50 51 bool cmp2(Node a, Node b) { 52 return a.id < b.id; 53 } 54 55 void solve(int s, LL X, LL &A, LL &B) { 56 repd(i, log2(n - s + 1), 0) 57 if (f[i][s].A + A + f[i][s].B + B <= X) { 58 A += f[i][s].A; 59 B += f[i][s].B; 60 s = f[i][s].to; 61 } 62 if (A + abs(H[jp1[s]] - H[s]) + B <= X) A += abs(H[jp1[s]] - H[s]); 63 } 64 65 int main() { 66 n = read(); 67 rep(i, 1, n) { 68 nd[i].v = H[i] = read(); 69 nd[i].id = i; 70 } 71 72 sort(nd + 1, nd + n + 1, cmp1); 73 74 rep(i, 2, n) L[nd[i].id] = nd[i-1].id; 75 rep(i, 1, n-1) R[nd[i].id] = nd[i+1].id; 76 L[0] = L[nd[1].id] = 0; 77 R[n+1] = R[nd[n].id] = n+1; 78 79 H[0] = H[n+1] = inf; 80 81 rep(i, 1, n) { 82 re int second = comp(i, L[i], R[i]); 83 re int first = comp(i, L[i] + R[i] - second, comp(i, L[L[i]], R[R[i]])); 84 jp1[i] = first, jp2[i] = second; 85 L[R[i]] = L[i]; 86 R[L[i]] = R[i]; 87 } 88 89 rep(i, 1, n) { 90 f[0][i].to = jp2[jp1[i]]; 91 f[0][i].A = abs(H[jp1[i]] - H[i]); 92 if (jp2[jp1[i]] == n+1) f[0][i].B = inf; 93 else f[0][i].B = abs(H[jp1[i]] - H[jp2[jp1[i]]]); 94 } 95 rep(x, 1, log2(n)) 96 rep(i, 1, n) { 97 f[x][i].to = f[x-1][f[x-1][i].to].to; 98 f[x][i].A = f[x-1][i].A + f[x-1][f[x-1][i].to].A; 99 f[x][i].B = f[x-1][i].B + f[x-1][f[x-1][i].to].B; 100 if (f[x][i].A > inf) f[x][i].A = inf*2; 101 if (f[x][i].B > inf) f[x][i].B = inf*2; 102 } 103 104 X0 = read(); 105 106 H[0] = -inf; 107 re LL maxi = 0, maxA = inf, maxB = 1; 108 109 rep(i, 1, n) { 110 #define update maxA = A, maxB = B, maxi = i 111 re LL A = 0, B = 0; 112 solve(i, X0, A, B); 113 if (B != 0) { 114 if ((double)maxA / maxB > (double)A / B) update; 115 else if (fabs((double)maxA / maxB - (double)A / B) < 1e-9 && H[i] > H[maxi]) update; 116 } 117 } 118 119 printf("%lld\n", maxi); 120 121 m = read(); 122 123 while (m--) { 124 re int s = read(); 125 re LL X = read(), A = 0, B = 0; 126 solve(s, X, A, B); 127 printf("%lld %lld\n", A, B); 128 } 129 130 return 0; 131 }

[NOIP2012]開車旅行