[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;
}

[LOJ3054] 「HNOI2019」鱼的更多相关文章

  1. Loj #3059. 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

  2. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

  3. Loj #3055. 「HNOI2019」JOJO

    Loj #3055. 「HNOI2019」JOJO JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 ...

  4. Loj 3058. 「HNOI2019」白兔之舞

    Loj 3058. 「HNOI2019」白兔之舞 题目描述 有一张顶点数为 \((L+1)\times n\) 的有向图.这张图的每个顶点由一个二元组 \((u,v)\) 表示 \((0\le u\l ...

  5. Loj #3057. 「HNOI2019」校园旅行

    Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...

  6. 【loj - 3056】 「HNOI2019」多边形

    目录 description solution accepted code details description 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时 ...

  7. 【loj - 3055】「HNOI2019」JOJO

    目录 description solution accepted code details description JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或 ...

  8. LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路+线段树上二分

    题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...

  9. LOJ 3057 「HNOI2019」校园旅行——BFS+图等价转化

    题目:https://loj.ac/problem/3057 想令 b[ i ][ j ] 表示两点是否可行,从可行的点对扩展.但不知道顺序,所以写了卡时间做数次 m2 迭代的算法,就是每次遍历所有不 ...

随机推荐

  1. VS调试的问题

    调试Vs,使用本地IIS也不行,使用外部服务器也不行,最后运行VS2013以管理员身份就可以了

  2. matlab的代码注释

    1.注释一块代码: %{ 此处代码块 %} 2.注释数行代码: 先选中,然后用组合键Ctrl+R 取消注释,用组合键Ctrl+T 3.双%%的作用:代码分块运行,点击双%%之间的代码,再点Run Se ...

  3. 2017SN多校D1T2 note:dp

    题意: 给你一个长度为n的字符串s,并且告诉你有m对字母不能相邻,问你最少在s中取出多少个字符能够使这个字符串合法. 题解: 表示状态: dp[i] = max num of letters 考虑到第 ...

  4. STM32中IO口的8中工作模式

    该文摘自:http://blog.csdn.net/kevinhg/article/details/17490273 一.推挽输出:可以输出高.低电平,连接数字器件:推挽结构一般是指两个三极管分别受两 ...

  5. (转)[sh] <defunct>进程

    我也碰到僵尸进程了,必须通过关闭僵尸进程的父进程或者重启解决. 来自:http://jerrybear.blog.51cto.com/629421/387846 今日发现服务器上多了一些名称为[sh] ...

  6. POJ3237 Tree(树剖+线段树+lazy标记)

    You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbe ...

  7. 【Lintcode】088.Lowest Common Ancestor

    题目: Given the root and two nodes in a Binary Tree. Find the lowest common ancestor(LCA) of the two n ...

  8. SQL 优化总结(三) SQL子句

    SQL子句 尽可能编写优化器可以优化的语句. 1. SELECT子句 (1) 在查询Select语句中用Where字句限制返回的行数,避免表扫描,如果返回不必要的数据,浪费了服务器的I/O资源,加重了 ...

  9. ZigBee自组网地址分配与路由协议概述

    1. ZigBee简介 ZigBee是基于IEEE802.15.4标准的低功耗局域网协议.根据国际标准规定,ZigBee技术是一种短距离.低功耗的无线通信技术. ZigBee协议从下到上分别为物理层( ...

  10. puppet初始化安装和配置(puppet自动化系列1)

    一.服务器规划 以下均直接yum安装最新版. 服务器操作系统为centos6.2 Puppetmaster1 10.168.32.116 puppstmaster1.jq.com Puppetmast ...