Problem

给你n个点的坐标和权值,然后一个点最多可以经过1次,最后要回到原点,求这条路径中包含的点的权值和除以路径长度的最大值。

Solution

我们可以很明显的得知,这条路径是个凸包(否则不但包含的点少了,路径也长了)
我们可以二分答案,然后用一个dp来验证答案:
所以我们用f[i]表示枚举到第i个点后的值,最后判断是否大于等于0

如果我们可以快速算出一个颜色的三角形内的点权之和,则这个DP是可以O(n^2)实现的。
我们可以用O(n^3)大暴力来预处理。(期望得分:60)
如果我们可以尝试用O(n^2logn)来预处理,那么就可以A了此题

如果k在这个三角形的内部,那么关于p的极角排序,k在j的前面,关于i的极角排序,k在j的后面,
那么这就转换成了一个二维数点问题,时间复杂度为O(n*(nlogn+nlogn))。(期望得分:100)

Notice

计算几何代码十分复杂

Code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define sqz main
#define ll long long
#define reg register int
#define lowbit(x) (x & -x)
#define rep(i, a, b) for (reg i = a; i <= b; i++)
#define per(i, a, b) for (reg i = a; i >= b; i--)
#define travel(i, u) for (reg i = head[u]; i; i = edge[i].next)
const int INF = 1e9, N = 2000;
const double eps = 1e-6, phi = acos(-1.0);
ll mod(ll a, ll b) {if (a >= b || a < 0) a %= b; if (a < 0) a += b; return a;}
ll read(){ ll x = 0; int zf = 1; char ch; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
void write(ll y) { if (y < 0) putchar('-'), y = -y; if (y > 9) write(y / 10); putchar(y % 10 + '0');}
int n, Sum[N + 5][N + 5];
double f[N + 5];
struct node
{
	int X[N + 5];
	void build(int l, int r)
	{
		rep(i, l, r) X[i] = 0;
	}
	void modify(int x, int y)
	{
		while(x < n)
		{
			X[x]+= y;
			x += lowbit(x);
		}
	}
	int query(int x)
	{
		int ans = 0;
		while (x)
		{
			ans += X[x];
			x -= lowbit(x);
		}
		return ans;
	}
}BIT;
struct point 
{
	double x, y;
	point(double x = 0, double y = 0) : x(x), y(y) {}
	friend double operator *(const point &X, const point &Y)
	{
		return X.x * Y.y - X.y * Y.x;
	}
	friend double operator %(const point &X, const point &Y) 
	{
		return X.x  * Y.x + X.y * Y.y;
	}
	friend point operator +(const point &X, const point &Y)
	{
		return point(X.x + Y.x, X.y + Y.y);
	}
	friend point operator -(const point &X, const point &Y)
	{
		return point(X.x - Y.x, X.y - Y.y);
	}
	double dis(const point &Y)
	{
		return sqrt((x - Y.x) * (x - Y.x) + (y - Y.y) * (y - Y.y));
	}
}Standard;
pair<point, int> T[N + 5], D[N + 5];
int cmp(pair<point, int> X, pair<point, int> Y)
{
	if (abs((X.first - Standard) * (Y.first - Standard)) < eps) return X.first.x < Y.first.x;
	else return (X.first - Standard) * (Y.first - Standard) > 0;
}
int calc(double mid)
{
	f[0] = 0; f[n] = -INF;
	rep(i, 1, n - 1) f[i] = T[i].second - mid * T[i].first.dis(T[0].first);
	rep(i, 1, n - 1)
		rep(j, i + 1, n)
			f[j] = max(f[j], f[i] + Sum[i][j] - mid * T[j].first.dis(T[i].first));
	return f[n] >= 0;
}
double find(double l, double r)
{
	if (abs(l - r) < eps) return l;
	double mid = (l + r) / 2;
	if (calc(mid)) return find(mid, r);
	else return find(l, mid);
}
int sqz() 
{
	n = read();
	Standard = point(0, 0);
	rep(i, 1, n)
	{
		int x = read(), y = read();
		T[i] = make_pair(point(x, y), read());
	}
	sort(T + 1, T + n + 1, cmp);
	T[0] = make_pair(point(0, 0), 0), T[++n] = T[0];
	rep(i, 1, n - 1)
	{
		Sum[i][n] = 0;
		rep(j, i + 1, n - 1) D[j] = make_pair(T[j].first, j);
		Standard = T[i].first;
		sort(D + i + 1, D + n, cmp);
		BIT.build(0, n);
		per(j, n - 1, i + 1)
		{
			BIT.modify(D[j].second, T[D[j].second].second);
			Sum[i][D[j].second] = BIT.query(D[j].second);
		}
	}
	printf("%.3lf\n", find((double)0, (double)2e8));
	return 0;
}
posted on 2017-10-30 13:41  WizardCowboy  阅读(114)  评论(0)    收藏  举报