【BZOJ4858】【JSOI2016】炸弹攻击 2

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/79964120

【题目链接】

【思路要点】

  • 枚举发射源,将发射源当做原点,对敌人和激光塔极角排序。
  • 由于敌人纵坐标均为正,而其它点均为负,因此每两个角度差在\(\pi\)以内的激光塔内部的敌人的个数之和就是该发射源对答案的贡献。
  • 用前缀和以及Two Pointers可以在\(O(N)\)的时间内统计一个发射源的贡献。
  • 时间复杂度\(O(N^2LogN)\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2005;
const double pi = acos(-1);
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct point {int x, y; };
point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; }
long long operator * (point a, point b) {return 1ll * a.x * b.y + 1ll * a.y * b.x; }
struct info {point pos; double alpha; bool type; };
info a[MAXN]; point p[MAXN];
int n, m, pre[MAXN];
double PolarAngle(point a) {return atan2(a.y, a.x); }
bool cmp(info a, info b) {return a.alpha < b.alpha; }
int main() {
	read(n);
	for (int i = 1; i <= n; i++) {
		read(a[i].pos.x), read(a[i].pos.y);
		a[i].type = true;
	}
	read(m);
	for (int i = 1; i <= m; i++)
		read(p[i].x), read(p[i].y);
	int k; read(k); n += k;
	for (int i = n - k + 1; i <= n; i++) {
		read(a[i].pos.x), read(a[i].pos.y);
		a[i].type = false;
	}
	long long ans = 0;
	for (int j = 1; j <= m; j++) {
		for (int i = 1; i <= n; i++)
			a[i].alpha = PolarAngle(a[i].pos - p[j]);
		sort(a + 1, a + n + 1, cmp);
		for (int i = 1; i <= n; i++)
			pre[i] = pre[i - 1] + a[i].type;
		long long sum = pre[1] * (!a[1].type), cnt = !a[1].type;
		for (int i = 1, j = 1; i <= n; i++) {
			if (j == i - 1) {
				j = i;
				if (!a[i].type) {
					cnt++;
					sum += pre[i];
				}
			}
			int k = j % n + 1;
			while (k != i && (k > i && a[k].alpha - a[i].alpha < pi || k < i && a[k].alpha - a[i].alpha + 2 * pi < pi)) {
				j = k;
				if (!a[k].type) {
					cnt++; sum += pre[k];
					if (k < i) sum += pre[n];
				}
				k = j % n + 1;
			}
			if (!a[i].type) {
				ans += sum - cnt * pre[i];
				cnt--; sum -= pre[i];
			}
		}
	}
	writeln(ans);
	return 0;
}

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页