Time Limit: 5000MS | Memory Limit: 262144KB | 64bit IO Format: %I64d & %I64u |
Description
Input
Output
Sample Input
3 3 1 2 2 1 5 1 1 4 3 1 3 2 2 5 1 1 4 3 1 4 2 3 5 1 1 4
Sample Output
Case #1: 101.3099324740 Case #2: 90.0000000000 Case #3: 78.6900675260
题目大意:
在一个平地上右n个摩天轮,题目告诉你每个摩天轮的位置,和高度,现在马特站在q个位置上,问马特站在每个位置上,他能看到最大仰望天空的角度为多少?
1<=N<=10^5 1<=Q<=10^5
解析:
这题的数据量很大,如果直接暴力的话肯定超时。
所以要用单调栈进行优化,将人和楼组合在一起,按照位置从小到大排序后,维护一个从左到右凸的高度下降的单调栈,然后每次查询到人的位置的时候,维护单调栈,使得图形是凸的,那么栈顶和人所构成的仰角就是正向答案。但是这只是正向的答案,所以反向扫描所有的位置,维护出一个从右到左凸的单调栈,求出反向的答案,和之前的结果相加就是最终答案。
总结:在做这题时把pi写成int类型了,白白浪费了一个下午的时间要好好吸取教训。
#include <cstdio> #include <cstring> #include <cmath> #include <stack> #include <algorithm> using namespace std; const int N = 100005 * 2; const double PI = acos(-1.0); struct Node { double x,y; int flag; }p[N],st[N]; double ans[N]; int n,q; bool cmp(Node a,Node b) { return a.x < b.x; } double getAngle(Node a,Node b) { return atan(fabs(b.x - a.x) / a.y); } double rate(Node a,Node b) { return (a.y - b.y) / (a.x - b.x); } bool judge_front(Node a,Node b,Node c) { double k1 = rate(a,b); double k2 = rate(a,c); if(k1 < 0 && k2 < 0 && fabs(k1) >= fabs(k2)) { return true; }else { return false; } } void solve_front() { int top = 0; for(int i = 0; i < n+q; i++) { if(p[i].flag) { while(top >= 2 && judge_front(st[top-2],st[top-1],p[i]) ) { top--; } ans[p[i].flag] += getAngle(st[top-1],p[i]); }else { while(top && st[top-1].y <= p[i].y) { top--; } while(top >= 2 && judge_front(st[top-2],st[top-1],p[i])) { top--; } st[top] = p[i]; top++; } } } bool judge_back(Node a,Node b,Node c) { double k1 = rate(a,b); double k2 = rate(a,c); if(k1 > 0 && k2 > 0 && fabs(k1) >= fabs(k2)) { return true; }else { return false; } } void solve_back() { int top = 0; for(int i = n+q-1; i >= 0; i--) { if(p[i].flag) { while(top >= 2 && judge_back(st[top-1],st[top-2],p[i]) ) { top--; } ans[p[i].flag] += getAngle(st[top-1],p[i]); }else { while(top && st[top-1].y <= p[i].y) { top--; } while(top >= 2 && judge_back(st[top-2],st[top-1],p[i])) { top--; } st[top++] = p[i]; } } } int main() { int t , cas = 1; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i = 0; i < n; i++) { scanf("%lf%lf",&p[i].x,&p[i].y); p[i].flag = 0; } scanf("%d",&q); for(int i = n; i < n+q; i++) { scanf("%lf",&p[i].x); p[i].y = 0; p[i].flag = i - n + 1; } sort(p,p+n+q,cmp); memset(ans,0,sizeof(ans)); solve_front(); solve_back(); printf("Case #%d:\n",cas++); for(int i = 1; i <= q; i++) { printf("%.10lf\n",ans[i] * 180 / PI); } } return 0; }