[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^2\log 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\n", ans * 4ll);
  return 0;
}
posted @ 2019-04-09 23:21  wawawa8  阅读(330)  评论(0编辑  收藏  举报