弱校联赛师大第一场 1002 SecKill

    本题在比赛过程中没什么思路,最后也没有AC,赛后在和中GG交流后发现是简单的几何 + 离散化 + 区间覆盖线性扫描,后面果断写之。但是悲剧的是一直WA,后面快回宿舍的时候发现我数组开小了,遍历的长度也太小了,最后回宿舍借了明福的笔记本重新敲了一遍,果断AC了。(*^__^*) 嘻嘻……,最近校赛被虐,弱校联赛被虐,鸭梨很大,以后要多加努力了,加油ACb0y。

 

题意:

      在二维平面坐标的第一象限中给定n个圆 0 < n < 30000,求经过原点的射线最多能穿过几个圆。

 

解法:

      对每个圆求两条切线的极角值(0. 0 ~ 90.0),然后把这些值离散后,问题就变成了,区间最多覆盖的求解,用线性扫描果断A之。

 

AC代码如下:

#include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <set> #include <map> using namespace std; struct circle { //圆的两条切线的两个极角值 double left; double right; //left和right离散后的整数值 int intLeft; int intRight; }; int n; circle d[30005]; //静态统计区间覆盖 int seg[30005 * 2]; //对所有的极角值进行排序nlogn set<double> s; //离散化使用的map映射 map<double ,int> m; int main() { double x, y, r; while (scanf("%d", &n) != EOF) { for (int i = 0; i < n; ++i) { scanf("%lf%lf%lf", &x, &y, &r); double temp = atan2(y, x); double temp1 = atan2(r, sqrt(x * x + y * y - r * r)); d[i].left = temp - temp1; d[i].right = temp + temp1; s.insert(d[i].left); s.insert(d[i].right); } set<double>::iterator it; int cnt = 0; //离散化 for (it = s.begin(); it != s.end(); ++it) { m[*it] = ++cnt; } for (int i = 0; i < n; ++i) { d[i].intLeft = m[d[i].left]; d[i].intRight = m[d[i].right]; } //区间覆盖线性扫描 memset(seg, 0, sizeof(seg)); for (int i = 0; i < n; ++i) { seg[d[i].intLeft] += 1; seg[d[i].intRight] -= 1; } int ans = 0; int sum = 0; for (int i = 1; i <= cnt; ++i) { sum += seg[i]; if (sum > ans) { ans = sum; } } cout << ans << endl; } return 0; } 

你可能感兴趣的:(iterator)