[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.

输出

The only line of output should contain a single integer — the maximum possible score a player could gain.

输入示例

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;
}

 

转载于:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5814755.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值