[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;
}
[LOJ3054] 「HNOI2019」鱼的更多相关文章
- Loj #3059. 「HNOI2019」序列
Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...
- Loj #3056. 「HNOI2019」多边形
Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...
- Loj #3055. 「HNOI2019」JOJO
Loj #3055. 「HNOI2019」JOJO JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 ...
- Loj 3058. 「HNOI2019」白兔之舞
Loj 3058. 「HNOI2019」白兔之舞 题目描述 有一张顶点数为 \((L+1)\times n\) 的有向图.这张图的每个顶点由一个二元组 \((u,v)\) 表示 \((0\le u\l ...
- Loj #3057. 「HNOI2019」校园旅行
Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...
- 【loj - 3056】 「HNOI2019」多边形
目录 description solution accepted code details description 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时 ...
- 【loj - 3055】「HNOI2019」JOJO
目录 description solution accepted code details description JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或 ...
- LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路+线段树上二分
题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...
- LOJ 3057 「HNOI2019」校园旅行——BFS+图等价转化
题目:https://loj.ac/problem/3057 想令 b[ i ][ j ] 表示两点是否可行,从可行的点对扩展.但不知道顺序,所以写了卡时间做数次 m2 迭代的算法,就是每次遍历所有不 ...
随机推荐
- CentOS 7 设置自定义开机启动,添加自定义系统服务
详细文档,http://www.linuxidc.com/Linux/2015-04/115937.htm 摘自: http://www.centoscn.com/CentOS/config/2015 ...
- Hadoop HA- hadoop集群部署
前期部署,至少准备3台服务器(可以是虚拟机) 1.linux系统环境准备 ip地址配置 hostname配置 hosts映射配置 关闭防火墙 service iptables stop ,也可以设置防 ...
- Android窗口系统第二篇---Window的添加过程
以前写过客户端Window的创建过程,大概是这样子的.我们一开始从Thread中的handleLaunchActivity方法开始分析,首先加载Activity的字节码文件,利用反射的方式创建一个Ac ...
- lucene内置的评分函数
For multiterm queries, Lucene takes the Boolean model, TF/IDF, and the vector space model and combin ...
- Linux_服务器_04_vim编辑器的使用
二.参考文档 1.linux系统中如何进入退出vim编辑器,方法及区别
- 使用top命令查看系统状态
Linux系统可以通过top命令查看系统的CPU.内存.运行时间.交换分区.执行的线程等信息.通过top命令可以有效的发现系统的缺陷出在哪里.是内存不够.CPU处理能力不够.IO读写过高? 使用SSH ...
- skynet实践(9)-随机数重复问题
最近在使用skynet的过程中,遇到需要为玩家的每次请求产生一个随机序列的场景.简化如下: main.lua中每隔1S便发出一次随机数请求: local skynet = require " ...
- linux命令学习笔记-md5sum 命令详解
前言 在网络传输.设备之间转存.复制大文件等时,可能会出现传输前后数据不一致的情况.这种情况在网络这种相对更 不稳定的环境中,容易出现.那么校验文件的完整性,也是势在必行的. 使用说明 md5sum命 ...
- Virtual Codeforces Round #392 (Div. 2)
下午闲来无事开了一场Virtual participation 2h就过了3道水题...又跪了..这只是Div. 2啊!!! 感觉这次直接就是跪在了读题上,T1,T2读题太慢,T3还把题读错了 要是让 ...
- 【Lintcode】153.Combination Sum II
题目: Given a collection of candidate numbers (C) and a target number (T), find all unique combination ...