[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. css(4)

    类选择器和id选择器都有父子选择器. 在css文件中国,有时候为了简化样式,可以把相同的样式拿出来放在一起. display:inline display:block 行内元素里只能放行内元素,而块内 ...

  2. 如何在u盘上安装系统, (非安装盘)

    在u盘中永久安装Fedora. 需要两个u盘(live usb), 一个系统镜像文件. 方法是: 用一个u盘作安装盘,  然后通过这个u盘把系统安装到另一个u盘上. 两个U盘上的文件都会被覆盖. 1. ...

  3. linux命令学习笔记(23):Linux 目录结构

    对于每一个Linux学习者来说,了解Linux文件系统的目录结构,是学好Linux的至关重要的一步.,深入了解linux文件 目录结构的标准和每个目录的详细功能,对于我们用好linux系统只管重要,下 ...

  4. 洛谷 P2962 [USACO09NOV]灯Lights

    题目描述 Bessie and the cows were playing games in the barn, but the power was reset and the lights were ...

  5. JavaScript中的eval()函数详解

    和其他很多解释性语言一样,JavaScript同样可以解释运行由JavaScript源代码组成的字符串,并产生一个值.JavaScript通过全局函数eval()来完成这个工作     eval(“1 ...

  6. codevs2189数字三角形w——最优性转化

    题目:http://codevs.cn/problem/2189/ 通过增加一维,将最优性转化为可行性. 代码如下: #include<iostream> #include<cstd ...

  7. cocos2dx unzip、createDir

    转自:http://www.cnblogs.com/xioapingguo/p/4037323.html static unsigned long _maxUnzipBufSize = 0x50000 ...

  8. JavaScript高级程序设计学习笔记第四章--变量、作用域和内存问题

    1.变量可能包含两种不同数据类型的值:基本类型值和引用类型值. 基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象. 2.变量复制 如果从一个变量向另一个变量复制基本类型的值,会在 ...

  9. linux命令配置IP详解

    在Linux系统中,TCP/IP网络是通过若干个文本文件进行配置的,有时需要编辑这些文件来完成联网工作. vi /etc/sysconfig/network-scripts/ifcfg-eth0 :进 ...

  10. 《Java多线程编程核心技术》读后感(十六)

    线程组 线程组的作用是,可以批量的管理线程或线程组对象,有效地对线程或线程组对象进行组织 线程对象关联线程组:1级关联 package Seven; public class ThreadA exte ...