[LOJ3054] 「HNOI2019」鱼

[LOJ3054] 「HNOI2019」鱼

连接

连接ios

题解

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

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

下面考虑 \((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;
}
相关文章
相关标签/搜索