题目
分析
这道题的要点在于:含原点的三角形不好数,我们数不含原点的三角形,最后用C(N,3)扣掉它就是答案了。
怎么数“不含原点的三角形”呢?
画出我们所在的坐标系。我们拿一条过原点的直线l,按极角序去扫描:
直线l分成两条射线,一个是a,另一个是b。它绕着原点(Bessie所在点)旋转,请自行想象在孙悟空手中旋转的金箍棒。
(猴哥,猴哥,你真了不得……)
然后关键在于:每当射线a扫到一个点P时,我们统计P和直线l“左侧”所有点形成的三角形(严格地讲,是和a叉积为正的半平面):
像这样,图中展示了a扫到p点时统计的三个三角形。
每一个不包含原点的三角形——无论形状多么畸形,位置多么奇特,总会被计入统计一次且只有一次。下面展示了几个三角形,和它们被计入统计时,扫描线a的位置:
(注意,这个点不一定是极角最小的点)
这样问题就好办了:先把所有点按照极角排序,然后线性扫描下去,用两个指针维护a和b的位置,在扫描的过程中,减掉所有应予统计的三角形。
代码
#include#include #include #include #include using namespace std; typedef long long LL; const int SIZEN=200010; class Point{ public: LL x,y; double ang; }; bool cmp(const Point &a,const Point &b){ return a.ang =0) j++; LL k=j-i-1; ans-=k*(k-1)/2; } printf("%lld\n",ans); } void read(void){ scanf("%d",&N); for(int i=1;i<=N;i++){ scanf("%lld%lld",&P[i].x,&P[i].y); P[i].ang=atan2(P[i].y+0.0,P[i].x+0.0); } } int main(){ freopen("tricount.in","r",stdin); freopen("tricount.out","w",stdout); read(); work(); return 0; }