#include <bits/stdc++.h> #define REP(i,n) for (int _n=(n), i=0;i<_n;++i) #define FOR(i,a,b) for (int i=(a),_b=(b);i<=_b;++i) #define FORD(i,a,b) for (int i=(a),_b=(b);i>=_b;--i) #define TRACE(x) std::cerr << "TRACE(" #x ")" << std::endl; #define DEBUG(x) std::cerr << #x << " = " << (x) << std::endl; void init_io() { std::cin.tie(nullptr); std::ios::sync_with_stdio(false); } struct Train { int begin = -1; int end = -1; }; std::vector<Train> left_trains; std::vector<Train> middle_trains; std::vector<Train> right_trains; // in meters / second int full_speed; int left_speed; int right_speed; std::int64_t fixed_point_denominator; class FixedPoint { public: explicit FixedPoint(int x = 0) : FixedPoint(x * fixed_point_denominator, FromQuanta{}) {} friend inline FixedPoint operator+(FixedPoint a, FixedPoint b) { return FixedPoint(a.val + b.val, FromQuanta{}); } void operator+=(FixedPoint b) { val += b.val; } friend inline FixedPoint operator-(FixedPoint a, FixedPoint b) { return FixedPoint(a.val - b.val, FromQuanta{}); } friend inline FixedPoint operator*(int a, FixedPoint b) { return FixedPoint(a * b.val, FromQuanta{}); } FixedPoint divide_exact(int x) const { assert(val % x == 0); return FixedPoint(val / x, FromQuanta{}); } static FixedPoint inverse(int x) { return FixedPoint(1).divide_exact(x); } friend inline bool operator<(FixedPoint a, FixedPoint b) { return a.val < b.val; } friend inline bool operator>(FixedPoint a, FixedPoint b) { return a.val > b.val; } friend inline bool operator<=(FixedPoint a, FixedPoint b) { return a.val <= b.val; } friend inline bool operator>=(FixedPoint a, FixedPoint b) { return a.val >= b.val; } double to_double() const { return static_cast<double>(val) / fixed_point_denominator; } private: class FromQuanta {}; explicit FixedPoint(std::int64_t v, FromQuanta): val(v) {} std::int64_t val; }; FixedPoint inverse_full_speed; FixedPoint inverse_left_speed; FixedPoint inverse_right_speed; std::vector<Train> read_trains(const int len) { std::vector<Train> trains; trains.reserve(len/2); { char first_char; std::cin >> first_char; } Train train; REP(i, len) { bool occupied = false; if (i < len-1) { char c; std::cin >> c; occupied = c == '#'; } if (occupied) { if (train.begin == -1) { train.begin = i; } } else { if (train.begin != -1) { train.end = i + 1; trains.push_back(train); train = Train{}; } } } return trains; } void read_input() { int len; int middle_speed; std::cin >> len >> full_speed >> left_speed >> middle_speed >> right_speed; full_speed -= middle_speed; left_speed -= middle_speed; right_speed = middle_speed - right_speed; assert(0 < left_speed && left_speed < full_speed && full_speed <= 140); assert(0 < right_speed && right_speed <= 140); // at most 140^5 < 54e9 fixed_point_denominator = static_cast<std::int64_t>(right_speed) * left_speed * full_speed * (full_speed - left_speed) * (full_speed + right_speed); // makes range of FixedPoint go up to 170 million inverse_full_speed = FixedPoint::inverse(full_speed); inverse_left_speed = FixedPoint::inverse(left_speed); inverse_right_speed = FixedPoint::inverse(right_speed); left_trains = read_trains(len); middle_trains = read_trains(len); right_trains = read_trains(len); } FixedPoint solve() { FixedPoint current_time{0}; int pos = 0; auto next_left_train = left_trains.begin(); auto next_right_train = right_trains.begin(); int prev_right_train_end = 0; for (const Train &middle_train : middle_trains) { // Catch up to the back of the middle train. current_time += (middle_train.begin - pos) * inverse_full_speed; pos = middle_train.begin; // Overtaking duration assuming we can go at full speed. const FixedPoint overtake_duration = (middle_train.end - pos) * inverse_full_speed; // Skip left trains that we have already passed -- we never have to hit them again. while (next_left_train != left_trains.end() && (pos - next_left_train->end) * inverse_left_speed >= current_time) { ++next_left_train; } // Assume we can go left at full speed. FixedPoint overtake_time = current_time + overtake_duration; // Check if we get stuck behind a left train. if (next_left_train != left_trains.end()) { const FixedPoint overtake_behind_left = (middle_train.end - next_left_train->begin) * inverse_left_speed; overtake_time = std::max(overtake_time, overtake_behind_left); } // overtake_time is now the best we can do on the left. // See if we can go right faster. for (;;) { FixedPoint shift_right_time = (prev_right_train_end - pos) * inverse_right_speed; shift_right_time = std::max(current_time, shift_right_time); const FixedPoint overtake_right_time = shift_right_time + overtake_duration; // Not fast enough. if (overtake_right_time >= overtake_time) break; // Are we hitting the next right train? if (next_right_train != right_trains.end() && (next_right_train->begin - middle_train.end) * inverse_right_speed < overtake_right_time) { // We would hit the next train on the right. // Going left is even slower, so we can never use space before the right train: skip that space // and repeat. prev_right_train_end = next_right_train->end; ++next_right_train; } else { // Not hitting: go right! overtake_time = overtake_right_time; break; } } current_time = overtake_time; pos = middle_train.end; } // We have passed all middle trains, pedal to the metal! FixedPoint finish_time = current_time; if (!left_trains.empty()) { // current_time <= 200000 (since we can just follow the last left train) // left_speed * current_time <= 28M // still fits in FixedPoint which goes up to 170M const FixedPoint pass_all_left = current_time + (FixedPoint(left_trains.back().end - pos) + left_speed * current_time) .divide_exact(full_speed - left_speed); finish_time = std::max(finish_time, pass_all_left); } if (!right_trains.empty()) { const FixedPoint pass_all_right = current_time + (FixedPoint(right_trains.back().end - pos) - right_speed * current_time) .divide_exact(full_speed + right_speed); finish_time = std::max(finish_time, pass_all_right); } return finish_time; } int main() { init_io(); read_input(); const FixedPoint res = solve(); std::cout << std::fixed << std::setprecision(15) << res.to_double() << "\n"; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | #include <bits/stdc++.h> #define REP(i,n) for (int _n=(n), i=0;i<_n;++i) #define FOR(i,a,b) for (int i=(a),_b=(b);i<=_b;++i) #define FORD(i,a,b) for (int i=(a),_b=(b);i>=_b;--i) #define TRACE(x) std::cerr << "TRACE(" #x ")" << std::endl; #define DEBUG(x) std::cerr << #x << " = " << (x) << std::endl; void init_io() { std::cin.tie(nullptr); std::ios::sync_with_stdio(false); } struct Train { int begin = -1; int end = -1; }; std::vector<Train> left_trains; std::vector<Train> middle_trains; std::vector<Train> right_trains; // in meters / second int full_speed; int left_speed; int right_speed; std::int64_t fixed_point_denominator; class FixedPoint { public: explicit FixedPoint(int x = 0) : FixedPoint(x * fixed_point_denominator, FromQuanta{}) {} friend inline FixedPoint operator+(FixedPoint a, FixedPoint b) { return FixedPoint(a.val + b.val, FromQuanta{}); } void operator+=(FixedPoint b) { val += b.val; } friend inline FixedPoint operator-(FixedPoint a, FixedPoint b) { return FixedPoint(a.val - b.val, FromQuanta{}); } friend inline FixedPoint operator*(int a, FixedPoint b) { return FixedPoint(a * b.val, FromQuanta{}); } FixedPoint divide_exact(int x) const { assert(val % x == 0); return FixedPoint(val / x, FromQuanta{}); } static FixedPoint inverse(int x) { return FixedPoint(1).divide_exact(x); } friend inline bool operator<(FixedPoint a, FixedPoint b) { return a.val < b.val; } friend inline bool operator>(FixedPoint a, FixedPoint b) { return a.val > b.val; } friend inline bool operator<=(FixedPoint a, FixedPoint b) { return a.val <= b.val; } friend inline bool operator>=(FixedPoint a, FixedPoint b) { return a.val >= b.val; } double to_double() const { return static_cast<double>(val) / fixed_point_denominator; } private: class FromQuanta {}; explicit FixedPoint(std::int64_t v, FromQuanta): val(v) {} std::int64_t val; }; FixedPoint inverse_full_speed; FixedPoint inverse_left_speed; FixedPoint inverse_right_speed; std::vector<Train> read_trains(const int len) { std::vector<Train> trains; trains.reserve(len/2); { char first_char; std::cin >> first_char; } Train train; REP(i, len) { bool occupied = false; if (i < len-1) { char c; std::cin >> c; occupied = c == '#'; } if (occupied) { if (train.begin == -1) { train.begin = i; } } else { if (train.begin != -1) { train.end = i + 1; trains.push_back(train); train = Train{}; } } } return trains; } void read_input() { int len; int middle_speed; std::cin >> len >> full_speed >> left_speed >> middle_speed >> right_speed; full_speed -= middle_speed; left_speed -= middle_speed; right_speed = middle_speed - right_speed; assert(0 < left_speed && left_speed < full_speed && full_speed <= 140); assert(0 < right_speed && right_speed <= 140); // at most 140^5 < 54e9 fixed_point_denominator = static_cast<std::int64_t>(right_speed) * left_speed * full_speed * (full_speed - left_speed) * (full_speed + right_speed); // makes range of FixedPoint go up to 170 million inverse_full_speed = FixedPoint::inverse(full_speed); inverse_left_speed = FixedPoint::inverse(left_speed); inverse_right_speed = FixedPoint::inverse(right_speed); left_trains = read_trains(len); middle_trains = read_trains(len); right_trains = read_trains(len); } FixedPoint solve() { FixedPoint current_time{0}; int pos = 0; auto next_left_train = left_trains.begin(); auto next_right_train = right_trains.begin(); int prev_right_train_end = 0; for (const Train &middle_train : middle_trains) { // Catch up to the back of the middle train. current_time += (middle_train.begin - pos) * inverse_full_speed; pos = middle_train.begin; // Overtaking duration assuming we can go at full speed. const FixedPoint overtake_duration = (middle_train.end - pos) * inverse_full_speed; // Skip left trains that we have already passed -- we never have to hit them again. while (next_left_train != left_trains.end() && (pos - next_left_train->end) * inverse_left_speed >= current_time) { ++next_left_train; } // Assume we can go left at full speed. FixedPoint overtake_time = current_time + overtake_duration; // Check if we get stuck behind a left train. if (next_left_train != left_trains.end()) { const FixedPoint overtake_behind_left = (middle_train.end - next_left_train->begin) * inverse_left_speed; overtake_time = std::max(overtake_time, overtake_behind_left); } // overtake_time is now the best we can do on the left. // See if we can go right faster. for (;;) { FixedPoint shift_right_time = (prev_right_train_end - pos) * inverse_right_speed; shift_right_time = std::max(current_time, shift_right_time); const FixedPoint overtake_right_time = shift_right_time + overtake_duration; // Not fast enough. if (overtake_right_time >= overtake_time) break; // Are we hitting the next right train? if (next_right_train != right_trains.end() && (next_right_train->begin - middle_train.end) * inverse_right_speed < overtake_right_time) { // We would hit the next train on the right. // Going left is even slower, so we can never use space before the right train: skip that space // and repeat. prev_right_train_end = next_right_train->end; ++next_right_train; } else { // Not hitting: go right! overtake_time = overtake_right_time; break; } } current_time = overtake_time; pos = middle_train.end; } // We have passed all middle trains, pedal to the metal! FixedPoint finish_time = current_time; if (!left_trains.empty()) { // current_time <= 200000 (since we can just follow the last left train) // left_speed * current_time <= 28M // still fits in FixedPoint which goes up to 170M const FixedPoint pass_all_left = current_time + (FixedPoint(left_trains.back().end - pos) + left_speed * current_time) .divide_exact(full_speed - left_speed); finish_time = std::max(finish_time, pass_all_left); } if (!right_trains.empty()) { const FixedPoint pass_all_right = current_time + (FixedPoint(right_trains.back().end - pos) - right_speed * current_time) .divide_exact(full_speed + right_speed); finish_time = std::max(finish_time, pass_all_right); } return finish_time; } int main() { init_io(); read_input(); const FixedPoint res = solve(); std::cout << std::fixed << std::setprecision(15) << res.to_double() << "\n"; } |