题目
http://acm.hdu.edu.cn/showproblem.php?pid=4445
分析
三分最远角度+二分命中区间+前缀和求最大值
对于每个炮弹,三分出最远距离的角度,然后在这个角度的两侧,分别有一个区间可以命中对应的目标
利用二分求出在两侧对应的区间
对于敌方目标的区间左端点事件点+1,右端点事件点-1
对于我方目标的区间左断点事件点-INF,右端点事件点+INF
同一个炮弹的敌方目标区间只计算一次,对事件点求前缀和,最大值即为答案
训练赛时只想到了后面二分和前缀和的部分,没想到前面对每个炮弹三分出最远的角度
代码
/************************************************** * Problem: HDU 4445 * Author: clavichord93 * State: Accepted **************************************************/ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #define sqr(a) ((a) * (a)) using namespace std; const double EPS = 1e-9; const double PI = acos(-1.0); const double DINF = 1e30; const int INF = 100000; inline int sgn(double a) { return a > EPS ? 1 : (a < -EPS ?-1 : 0); } const int MAX_N = 205; const double g = 9.8; struct Event { double ang; int value, id; Event() {} Event(double _ang, int _value, int _id) : ang(_ang), value(_value), id(_id) {} bool operator < (const Event &a) const { return sgn(ang - a.ang) < 0; } }; double H, L1, R1, L2, R2; int n; int cntAng; double v[MAX_N]; Event ang[MAX_N * 8]; int cnt[MAX_N]; double f(double v, double ang) { double A = g / (2.0 * sqr(v) * sqr(cos(ang))); double B = -tan(ang); double C = -H; double delta = B * B - 4.0 * A * C; return (-B + sqrt(delta)) / (2.0 * A); } double find1(double l, double r, double limit, double v) { double ans = r; while (l <= r) { double mid = 0.5 * (l + r); double x = f(v, mid); if (sgn(x - limit) >= 0) { ans = mid; r = mid - EPS; } else { l = mid + EPS; } } return ans; } double find2(double l, double r, double limit, double v) { double ans = l; while (l <= r) { double mid = 0.5 * (l + r); double x = f(v, mid); if (sgn(x - limit) <= 0) { ans = mid; r = mid - EPS; } else { l = mid + EPS; } } return ans; } int main() { #ifdef LOCAL_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif while (scanf("%d", &n), n) { memset(cnt, 0, sizeof(cnt)); scanf("%lf %lf %lf %lf %lf", &H, &L1, &R1, &L2, &R2); for (int i = 0; i < n; i++) { scanf("%lf", &v[i]); } cntAng = 0; for (int i = 0; i < n; i++) { double l = -0.5 * PI + EPS, r = 0.5 * PI - EPS; double ans = -0.5 * PI; while (l <= r) { double length = (r - l) / 3.0; double x1 = l + length; double x2 = l + 2.0 * length; double f1 = f(v[i], x1); double f2 = f(v[i], x2); //printf("f[%.10f] = %.10f, f[%.10f] = %.10f\n", x1, f1, x2, f2); if (sgn(f1 - f2) >= 0) { ans = x1; r = x2 - EPS; } else { ans = x2; l = x1 + EPS; } } double maxDist = f(v[i], ans); //printf("%.10f, %.10f\n", ans, maxDist); double angle; if (sgn(maxDist - L1) >= 0) { angle = find1(-0.5 * PI + EPS, ans, L1, v[i]); ang[cntAng++] = Event(angle, 1, i); angle = find2(ans, 0.5 * PI - EPS, L1, v[i]); ang[cntAng++] = Event(angle, -1, i); if (sgn(maxDist - R1) >= 0) { angle = find1(-0.5 * PI + EPS, ans, R1, v[i]); ang[cntAng++] = Event(angle, -1, i); angle = find2(ans, 0.5 * PI - EPS, R1, v[i]); ang[cntAng++] = Event(angle, 1, i); } else { ang[cntAng++] = Event(ans, -1, i); ang[cntAng++] = Event(ans, 1, i); } } if (sgn(maxDist - L2) >= 0) { angle = find1(-0.5 * PI + EPS, ans, L2, v[i]); ang[cntAng++] = Event(angle, -INF, i); angle = find2(ans, 0.5 * PI - EPS, L2, v[i]); ang[cntAng++] = Event(angle, INF, i); if (sgn(maxDist - R2) >= 0) { angle = find1(-0.5 * PI + EPS, ans, R2, v[i]); ang[cntAng++] = Event(angle, INF, i); angle = find2(ans, 0.5 * PI - EPS, R2, v[i]); ang[cntAng++] = Event(angle, -INF, i); } else { ang[cntAng++] = Event(ans, INF, i); ang[cntAng++] = Event(ans, -INF, i); } } } sort(ang, ang + cntAng); //for (int i = 0; i < cntAng; i++) { //printf("%.10f %d %d\n", ang[i].ang, ang[i].value, ang[i].id); //} int ans = 0; int sum = 0; for (int i = 0; i <cntAng; i++) { if (ang[i].value == 1) { cnt[ang[i].id]++; if (cnt[ang[i].id] == 1) { sum += ang[i].value; } } if (ang[i].value == -1) { cnt[ang[i].id]--; if (cnt[ang[i].id] == 0) { sum += ang[i].value; } } if (ang[i].value == -INF || ang[i].value == INF) { sum += ang[i].value; } if (ans < sum) { ans = sum; } } printf("%d\n", ans); } return 0; }