zoukankan      html  css  js  c++  java
  • 2016 Multi-University Training Contest 2

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5738

    题目大意:给定平面上的n个点,一个集合合法当且仅当集合中存在一对点u,v,对于集合中任意点w,均有dis(u,v)≥[dis(u,v)+dis(u,w)+dis(v,w)]/2。其中dis(A,B)为A,B两点的欧几里得距离。问你这样的合法集合有多少个。数据范围:1≤n≤1000。

    解题思路:对于所给条件简单分析一下就能转化题意,实际上是在求有多少个集合满足集合内的点都在同一直线上。

    比赛时的思路一直是,由于可能有重点,于是把重点整合到一个集合里,记一下集合里的个数cnt,那么对于这样一个重点的集合,从中任选至少两个都能作为合法点集,因此对答案的贡献是(2^cnt - cnt - 1)。下面考虑非重点,枚举重点集,对其他重点集按到此点集的距离从小到大排序,再依次枚举,用map记录一下斜率,就能在枚举过程中得到两个重点集之间的点个数K(也就是有多少个点也是这个斜率),对答案的贡献就是(2^cnt1 - 1)*(2^cnt2 - 1)*(2^K)。这样做思路应该没什么问题,只是常数比较大,代码难度也不小。一直到比赛结束也一直WA。

    后来看了题解,思路比较清楚。对于这种数方案,要不重不漏的题目要记得使用有序化思想。而在二维坐标中,很常用的两种排序就是x,y双关键字排序,还有极角排序。

    首先我们对这n个点做双关键字排序,然后对于x相同的点,个数为cnt,那么对答案的贡献就是(2^cnt - cnt - 1),然后对于每个重点集,对它右面的点做极角排序,做这个排序的意义在于以下就把同一斜率的点搞到了一起,方便计算了。假设当前极角上有p个点那么对答案的贡献就是(2^cnt - 1)*(2^p - 1)。

    值得注意的也是十分重要的,就是极角排序的正确做法。首先计算dx, dy,并除掉abs(gcd(dx,dy)),一定要取绝对值!!不然会WA得不明所以!!然后cmp()的时候不要把斜率化成小数比较,直接dyA*dxB<dxA*dyB这样比较可避免精度问题。

    总之这道题思想难度不是很大,但是需要的技巧比较多,细节也比较多,是值得一写的题目。

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 using namespace std;
     7 typedef long long LL;
     8 
     9 const int MaxN = 1000, Pt = 1e9 + 7;
    10 struct Point {
    11     int x, y, dx, dy;
    12 }a[MaxN + 5], b[MaxN + 5];
    13 int T, n;
    14 LL Pow[MaxN + 5];
    15 LL ans;
    16 
    17 int Gcd(int x, int y)
    18 {
    19     if (y == 0) return x;
    20     return Gcd(y, x % y);
    21 }
    22 
    23 void Init()
    24 {
    25     scanf("%d", &n);
    26     Pow[0] = 1;
    27     for (int i = 1; i <= n; i++) {
    28         scanf("%d%d", &a[i].x, &a[i].y);
    29         Pow[i] = (Pow[i - 1] * 2) % Pt;
    30     }
    31 }
    32 
    33 bool cmp(Point A, Point B) {
    34     if (A.x == B.x) return A.y < B.y;
    35     return A.x < B.x;
    36 }
    37 
    38 bool cmp2(Point A, Point B) {
    39     return (LL)A.dy * B.dx < (LL)A.dx * B.dy;
    40 }
    41 
    42 void Solve()
    43 {
    44     ans = 0;
    45     sort(a + 1, a + n + 1, cmp);
    46     int L = 1, R = 1;
    47     while (L <= n) {
    48         while (R < n && a[R + 1].x == a[R].x) R++;
    49         //printf("%d %d
    ", L, R);
    50         ans = (ans + Pow[R - L + 1] - 1 - (R - L + 1)) % Pt;
    51         int l = L, r = L;
    52         while (l <= R) {
    53             while (r < R && a[r + 1].y == a[r].y) r++;
    54             //printf("**%d %d
    ", l, r);
    55             int tot = 0;
    56             for (int i = R + 1; i <= n; i++) {
    57                 b[++tot].dx = a[i].x - a[l].x;
    58                 b[tot].dy = a[i].y - a[l].y;
    59                 int D = Gcd(b[tot].dx, b[tot].dy);
    60                 if (D < 0) D = -D;
    61                 b[tot].dx /= D; b[tot].dy /= D;
    62             }
    63             sort(b + 1, b + tot + 1, cmp2);
    64             int cnt = 1;
    65             for (int i = 1; i <= tot; i++) {
    66                 if (i == tot || cmp2(b[i], b[i + 1])) {
    67                     ans = (ans + (Pow[r - l + 1] - 1) * (Pow[cnt] - 1)) % Pt;
    68                     cnt = 1;
    69                 }else cnt++;
    70             }
    71             l = r + 1; r = r + 1;
    72         }
    73         L = R + 1; R = R + 1;
    74     }
    75     printf("%I64d
    ", ans);
    76 }
    77 
    78 int main()
    79 {
    80     scanf("%d", &T);
    81     for (int i = 1; i <= T; i++) {
    82         Init();
    83         Solve();
    84     }
    85 }
  • 相关阅读:
    SpringMVC从Request域中获取数据
    SpringMVC重定向
    SpringMVC的请求转发的三种方法
    SpringMVC文件上传
    SpringMVC处理请求释放静态资源的三种方式
    jackson实现json转换
    SpringMVC之请求部分
    SpringMVC的执行流程
    Java [Leetcode 39]Combination Sum
    深入解析Java对象的hashCode和hashCode在HashMap的底层数据结构的应用
  • 原文地址:https://www.cnblogs.com/ChopsticksAN/p/5693442.html
Copyright © 2011-2022 走看看