【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
0 0
1 2
0 2
1 0
1 1
Sample Output
7.0
题解:我们将所有点按x排序,枚举最左面的点。设当前点为i,我们想计算右面所有点对与其形成三角形的面积和。回忆起叉积的式子了吗?我们其实就是想计算$sumlimits_{j>i}sumlimits_{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 ",ans>>1,(ans&1)?5:0); return 0; }