• [LOJ3054] 「HNOI2019」鱼


    [LOJ3054] 「HNOI2019」鱼

    链接

    链接

    题解

    首先想 (O(n^3)) 的暴力,不难发现枚举 (A)(D) 后, ((B,C))((E,F)) 两组点互相之间没有影响,因此可以分开计算,对于任意一组点,枚举其中一个点,另一个点即为枚举的点关于 (AD) 的对称点,暴力统计即可

    然后首先考虑 ((E,F)) 一组点。由于有 (angle ADE, angle ADF gt 90 degree) 的限制,那么 (E,F) 两个点被限制在一个半平面内。考虑先枚举 (D) 再按照极角序枚举 (A),那么每个点进入可用半平面一次离开可用半平面一次,复杂度 (O(n^2))

    下面考虑 ((B, C)) 一组点。如果 (A,D) 确定了,那么相当于确定了 (BC) 的斜率。可以预处理枚举所有的 (B,C) 并按斜率归类,并且由于每一组 (B,C) 的斜率都相同,那么其所能对应的 (AD) 的斜率也相同,又 (BC) 的中点在 (AD) 上,所以对于确定的 (BC) 可以确定出 (AD) 所在直线。按照所在直线归类,每一类中按照 (BC) 的中点的 (x) 坐标排序,那么当 (AD) 确定时,仅需在其对应的一类中查询中点坐标在 (AD) 之间的所有 (B,C) 并统计个数,可以二分出结果,复杂度 (O(n^2log n^2))

    代码

    // Copyright lzt
    #include <stdio.h>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <set>
    #include <cmath>
    #include <iostream>
    #include <queue>
    #include <string>
    #include <ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef pair<long long, long long> pll;
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define rep(i, j, k) for (register int i = (int)(j); i <= (int)(k); i++)
    #define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
    #define Debug(...) fprintf(stderr, __VA_ARGS__)
    
    inline ll read()
    {
      ll x = 0, f = 1;
      char ch = getchar();
      while (ch < '0' || ch > '9')
      {
        if (ch == '-')
          f = -1;
        ch = getchar();
      }
      while (ch <= '9' && ch >= '0')
      {
        x = 10 * x + ch - '0';
        ch = getchar();
      }
      return x * f;
    }
    struct P
    {
      long long x, y;
      long long len() { return 1ll * x * x + 1ll * y * y; }
    } a[1009];
    
    long long ans;
    vector<int> p[1009][1009], v[1009][1009];
    long long n, id[1009], nw, cnt[1009][1009][2], CNT, po, PO, tot, val[1000061], ID[1000061];
    P dir[1000061];
    bool bo[1009];
    
    int nxt(int x) { return x == n ? 2 : x + 1; }
    long long operator^(P a, P b) { return 1ll * a.x * b.y - 1ll * a.y * b.x; }
    P operator-(P a, P b) { return (P){a.x - b.x, a.y - b.y}; }
    P operator*(P a, int b) { return (P){a.x * b, a.y * b}; }
    bool cmp(int x, int y) { return (a[x] - a[nw]).len() < (a[y] - a[nw]).len(); }
    bool check(int x) { return a[x].x > a[nw].x || a[x].x == a[nw].x && a[nw].y < a[x].y; }
    bool CHECK(int x) { return dir[x].x > a[nw].x || dir[x].x == a[nw].x && a[nw].y < dir[x].y; }
    bool Check(P x) { return x.x > a[nw].x || x.x == a[nw].x && a[nw].y < x.y; }
    bool Check2(P x) { return x.x > a[nw].x || x.x == a[nw].x && a[nw].y > x.y; }
    
    bool CMP(int x, int y)
    {
      if (check(x) ^ check(y))
        return check(x);
      return ((a[x] - a[nw]) ^ (a[y] - a[nw])) < 0;
    }
    
    bool PMC(int x, int y)
    {
      if (CHECK(x) ^ CHECK(y))
        return CHECK(x);
      return ((dir[x] - a[nw]) ^ (dir[y] - a[nw])) < 0;
    }
    
    bool Cmp(P x, P y)
    {
      if (Check(x) ^ Check(y))
        return Check(x);
      return ((x - a[nw]) ^ (y - a[nw])) <= 0;
    }
    
    bool Cmp2(P x, P y)
    {
      if (Check2(x) ^ Check2(y))
        return Check2(x);
      return ((x - a[nw]) ^ (y - a[nw])) < 0;
    }
    
    void ins(int j)
    {
      if (bo[j])
        return;
      bo[j] = 1;
      for (int k = 0, sz = v[nw][j].size(); k < sz; k++)
        if (bo[v[nw][j][k]])
          CNT++;
    }
    void del(int j)
    {
      if (!bo[j])
        return;
      bo[j] = 0;
      for (int k = 0, sz = v[nw][j].size(); k < sz; k++)
        if (bo[v[nw][j][k]])
          CNT--;
    }
    
    int main()
    {
      scanf("%lld", &n), ans = 0;
      for (int i = 1; i <= n; i++)
        scanf("%lld%lld", &a[i].x, &a[i].y);
      for (int i = 1; i <= n; i++)
      {
        for (int j = 1; j <= n; j++)
          id[j] = j;
        nw = i, sort(id + 1, id + 1 + n, cmp);
        for (int j = 2; j <= n; j++)
          for (int k = j - 1; (a[id[j]] - a[nw]).len() == (a[id[k]] - a[nw]).len(); k--)
            if (((a[id[j]] - a[nw]) ^ (a[id[k]] - a[nw])) != 0)
            {
              tot = 0;
              if (id[j] > id[k])
                swap(j, k), tot = 1;
              p[id[j]][id[k]].push_back(i), v[i][id[j]].push_back(id[k]), v[i][id[k]].push_back(id[j]);
              if (tot)
                swap(j, k);
            }
      }
      for (int i = 1; i <= n; i++)
        for (int j = i + 1; j <= n; j++)
        {
          cnt[i][j][0] = cnt[i][j][1] = 0;
          for (int k = 0, sz = p[i][j].size(); k < sz; k++)
            if (((a[i] - a[j]) ^ (a[i] - a[p[i][j][k]])) > 0)
              cnt[i][j][0]++;
            else
              cnt[i][j][1]++;
        }
      for (int i = 1; i <= n; i++)
      {
        n += 8;
        memset(bo, 0, sizeof(bo)), tot = 1;
        for (int j = 1; j <= n - 8; j++)
          if (i != j)
            id[++tot] = j;
        a[id[++tot] = (n - 7)] = (P){a[i].x + 1, a[i].y};
        a[id[++tot] = (n - 6)] = (P){a[i].x, a[i].y - 1};
        a[id[++tot] = (n - 5)] = (P){a[i].x - 1, a[i].y};
        a[id[++tot] = (n - 4)] = (P){a[i].x, a[i].y + 1};
        a[id[++tot] = (n - 3)] = (P){a[i].x + 1, a[i].y + 1};
        a[id[++tot] = (n - 2)] = (P){a[i].x + 1, a[i].y - 1};
        a[id[++tot] = (n - 1)] = (P){a[i].x - 1, a[i].y - 1};
        a[id[++tot] = n] = (P){a[i].x - 1, a[i].y + 1};
        nw = i, sort(id + 2, id + 1 + n, CMP), CNT = 0, po = n;
        for (int j = 2; j <= n; j++)
          if (a[id[j]].x > a[i].x)
            ins(id[po = j]);
        PO = 2, tot = 0;
        rep(j, 1, n) rep(k, 1, n) {
          if (j == k) continue;
        }
        rep(j, 1, n) rep(k, 1, n) {
          if (j == k) continue;
        }
        rep(j, 1, n) rep(k, 1, n) {
          if (j == k) continue;
        }
        for (int j = 1; j <= n; j++)
          for (int k = 0, sz = v[i][j].size(), X; k < sz; k++)
            if (v[i][j][k] > j)
            {
              X = v[i][j][k];
              dir[++tot] = (P){a[j].x + a[X].x - a[i].x - a[i].x, a[j].y + a[X].y - a[i].y - a[i].y};
              dir[tot] = (P){a[i].x + dir[tot].y, a[i].y - dir[tot].x};
              if (((a[j] - a[X]) ^ (a[j] - a[i])) > 0)
                val[tot] = cnt[j][X][1];
              else
                val[tot] = cnt[j][X][0];
            }
        dir[++tot] = (P){a[i].x, a[i].y + 1}, val[tot] = 0;
        dir[++tot] = (P){a[i].x + 1, a[i].y}, val[tot] = 0;
        dir[++tot] = (P){a[i].x, a[i].y - 1}, val[tot] = 0;
        dir[++tot] = (P){a[i].x - 1, a[i].y}, val[tot] = 0;
        dir[++tot] = (P){a[i].x + 1, a[i].y + 1}, val[tot] = 0;
        dir[++tot] = (P){a[i].x + 1, a[i].y - 1}, val[tot] = 0;
        dir[++tot] = (P){a[i].x - 1, a[i].y - 1}, val[tot] = 0;
        dir[++tot] = (P){a[i].x - 1, a[i].y + 1}, val[tot] = 0;
        for (int j = 1; j <= tot; j++)
          ID[j] = j;
        sort(ID + 1, ID + 1 + tot, PMC);
        int en = nxt(po);
        bool BO = 0;
        for (int j = 2; j <= n; j++)
          if (!check(id[j]) || a[id[j]].x > a[i].x)
          {
            PO = j;
            break;
          }
        for (int j = 1; j <= tot; j++)
        {
          while ((!BO || nxt(po) != en) && Cmp2((P){a[i].x * 2 - dir[ID[j]].x, dir[ID[j]].y},
                                                (P){a[id[nxt(po)]].x, a[i].y * 2 - a[id[nxt(po)]].y}))
            BO = 1, ins(id[po = nxt(po)]);
          while (PO <= n && Cmp(a[id[PO]], dir[ID[j]]))
            del(id[PO]), PO++;
          ans += 1ll * CNT * val[ID[j]];
        }
        n -= 8;
      }
      printf("%lld
    ", ans * 4ll);
      return 0;
    }
    
  • 相关阅读:
    网站制作常用的cms系统有哪些?
    企业网站建设中CMS系统的作用及现状
    PageAdmin企业网站制作中踩过的坑
    怎样制作网站的流程和步骤
    PageAdmin CMS建站系统可视化区块的使用教程
    PageAdmin CMS建站系统的可视化编辑体验
    企业网站建设常用CMS建站系统推荐
    PageAdmin CMS内容管理系统v4.0.11体验评测
    文本框检测回车按键或条码扫描结束回车符
    主播说联播 :铭记历史是为了创造历史 这三样东西不能丢!
  • 原文地址:https://www.cnblogs.com/wawawa8/p/10680572.html
Copyright © 2020-2023  润新知