[codeforces 241]C. Mirror Box
[codeforces 241]C. Mirror Box
试题描述
Mirror Box is a name of a popular game in the Iranian National Amusement Park (INAP). There is a wooden box, 105 cm long and 100cm high in this game. Some parts of the box's ceiling and floor are covered by mirrors. There are two negligibly small holes in the opposite sides of the box at heights hl and hr centimeters above the floor. The picture below shows what the box looks like.
In the game, you will be given a laser gun to shoot once. The laser beam must enter from one hole and exit from the other one. Each mirror has a preset number vi, which shows the number of points players gain if their laser beam hits that mirror. Also — to make things even funnier — the beam must not hit any mirror more than once.
Given the information about the box, your task is to find the maximum score a player may gain. Please note that the reflection obeys the law "the angle of incidence equals the angle of reflection".
输入
The first line of the input contains three space-separated integers hl, hr, n (0 < hl, hr < 100, 0 ≤ n ≤ 100) — the heights of the holes and the number of the mirrors.
Next n lines contain the descriptions of the mirrors. The i-th line contains space-separated vi, ci, ai, bi; the integer vi (1 ≤ vi ≤ 1000) is the score for the i-th mirror; the character ci denotes i-th mirror's position — the mirror is on the ceiling if ci equals "T" and on the floor if ci equals "F"; integers ai and bi (0 ≤ ai < bi ≤ 105) represent the x-coordinates of the beginning and the end of the mirror.
No two mirrors will share a common point. Consider that the x coordinate increases in the direction from left to right, so the border with the hole at height hl has the x coordinate equal to 0 and the border with the hole at height hr has the x coordinate equal to 105.
输出
输入示例
80 72 9 15 T 8210 15679 10 F 11940 22399 50 T 30600 44789 50 F 32090 36579 5 F 45520 48519 120 F 49250 55229 8 F 59700 80609 35 T 61940 64939 2 T 92540 97769
输出示例
120
数据规模及约定
见“输入”
题解
因为光线不能两次触碰到同一面镜子,所以拐点不会超过 n 个,我们不妨枚举拐点个数。确定了拐点个数后,我们设 t 是一个完整斜边(从底边反射上来再触碰到顶)在底边上投影的距离,不难列出一个一元一次方程,把 t 解出来后再遍历一遍每个镜子检查答案是否合法,合法就更新最优得分。枚举拐点个数 O(n),检查合法性 O(n),总时间复杂度 O(n2).
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 110 #define len 100000 const double eps = 1e-6; int h1, h2, n, cu, cd, ans; struct Mirror { int v, l, r; bool operator < (const Mirror& t) const { return l < t.l; } } up[maxn], down[maxn]; void check(bool cur, double t, double st) { bool ok = 0; int lu = 1, lastu = 0, ld = 1, lastd = 0, tmp = 0; for(; st - len < eps && (lu <= cu || ld <= cd);) { if(cur) { while(lu < cu && st - up[lu].r > eps) lu++; if(st - up[lu].l < eps || st - up[lu].r > eps || lu == lastu) return ; tmp += up[lu].v; lastu = lu; } else { while(ld < cd && st - down[ld].r > eps) ld++; if(st - down[ld].l < eps || st - down[ld].r > eps || ld == lastd) return ; tmp += down[ld].v; lastd = ld; } st += t; cur ^= 1; } ans = max(ans, tmp); return ; } int main() { h1 = read(); h2 = read(); n = read(); for(int i = 1; i <= n; i++) { int v = read(); char tp = getchar(); while(!isalpha(tp)) tp = getchar(); if(tp == 'T') up[++cu].v = v, up[cu].l = read(), up[cu].r = read(); if(tp == 'F') down[++cd].v = v, down[cd].l = read(), down[cd].r = read(); } sort(up + 1, up + cu + 1); sort(down + 1, down + cd + 1); for(int k = 0; k <= n; k++) { // down 0; up 1; double t; if(k & 1) { t = (double)len / ((double)h1 / 100.0 + (100.0 - h2) / 100.0 + k); check(0, t, t * h1 / 100.0); t = (double)len / ((100.0 - h1) / 100.0 + (double)h2 / 100.0 + k); check(1, t, t * (100.0 - h1) / 100.0); } else { t = (double)len / ((double)h1 / 100.0 + (double)h2 / 100.0 + k); check(0, t, t * h1 / 100.0); t = (double)len / ((100.0 - h1) / 100.0 + (100.0 - h2) / 100.0 + k); check(1, t, t * (100.0 - h1) / 100.0); } } printf("%d\n", ans); return 0; }