【BZOJ1132】[POI2008]Tro 几何

【BZOJ1132】[POI2008]Tro

Description

平面上有N个点. 求出所有以这N个点为顶点的三角形的面积和 N<=3000

Input

第一行给出数字N,N在[3,3000] 下面N行给出N个点的坐标,其值在[0,10000]

Output

保留一位小数,误差不超过0.1

Sample Input

5
0 0
1 2
0 2
1 0
1 1

Sample Output

7.0

题解:我们将所有点按x排序,枚举最左面的点。设当前点为i,我们想计算右面所有点对与其形成三角形的面积和。回忆起叉积的式子了吗?我们其实就是想计算$\sum\limits_{j>i}\sum\limits_{k>j}|aj*bk-ak*bj|$,其中aj=xj-xi,以此类推。

但是有绝对值怎么办?按斜率排序去绝对值即可。然后呢?前缀和优化一下就行了。

由于卡精,本题坐标要用int,斜率用double,答案用long long,并且输出的时候要当成整数输出!

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=3010;
typedef long long ll;
int n;
struct point
{
	int x,y;
	double a;
	point() {}
	point(int _1,int _2) {x=_1,y=_2,a=!x?1e10:(double)y/x;}
}p[maxn],q[maxn];
ll ans,sx,sy;
bool cmpx(point a,point b)
{
	return (a.x==b.x)?(a.y<b.y):(a.x<b.x);
}
bool cmpa(point a,point b)
{
	return a.a<b.a;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
int main()
{
	n=rd();
	int i,j;
	for(i=1;i<=n;i++)	p[i].x=rd(),p[i].y=rd();
	sort(p+1,p+n+1,cmpx);
	for(i=1;i<=n-2;i++)
	{
		for(j=i+1;j<=n;j++)	q[j-i]=point(p[j].x-p[i].x,p[j].y-p[i].y);
		sort(q+1,q+n-i+1,cmpa);
		for(sx=sy=0,j=n-i;j;j--)	ans+=q[j].x*sy-sx*q[j].y,sy+=q[j].y,sx+=q[j].x;
	}
	printf("%lld.%d\n",ans>>1,(ans&1)?5:0);
	return 0;
}

 

posted @ 2017-09-10 15:15  CQzhangyu  阅读(204)  评论(0编辑  收藏  举报