How Many Triangles HDU - 5784

主要在這個雙指針掃描法上,它的意思是說把左右邊界找到,然後在這個區間內的就是符合條件的,(據說比二分優越)

這個開2倍邊界掙扎了我好久.

代碼是一個鈍角/直角貢獻了兩個銳角的辦法,銳角-2*鈍/直 再/3就是數量

也可以用 銳角/3 - 鈍/直

複雜度(n^2)*log(n)

還有就是這個EPS,根據dls的直播課所說現在x和y上界是1e9,atan2(1e9,1)和atan2(1e9-1,1)的精度是在1/(1e9^2)也就是1e-18級別.

EPS別開的太小.

 

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double DB;
const DB PI = acos(-1.0);
const DB EPS = 1e-13;
int n;
struct NODE
{
    DB x,y;
} a[2003];
DB sign(DB x)
{
    if(abs(x)<= EPS)
        return 0;
    return x<0?-1:1;
}
double node[4003];
int CNT(DB A)
{
    int r = 1,res = 0;
    for(int l=1; l<n; l++)
    {
        int ecnt = 0;
        while( sign(node[l+ecnt]-node[l]) == 0)++ecnt;
        l = l+ecnt-1;//最後一個共線的點
        r = max(l+1,r);//開始第一個
        while(r-l+1 < n && sign(node[r]-node[l]-A)<0)r++;
        res += (r-l-1)*ecnt;
    }
    return res;
}
int main()
{
//    freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);

    while(cin>>n)
    {
        for(int i=1; i<=n; i++)
            cin>>a[i].x>>a[i].y;
        LL ans = 0,notans = 0;
        for(int i=1; i<=n; i++)
        {
            int cnt = 0;
            for(int j=1; j<=n; j++)
            {
                if(i == j)continue;
                node[++cnt] = atan2(a[i].y-a[j].y,a[i].x-a[j].x);
            }
            sort(node+1,node+cnt+1);
            for(int j=cnt+1; j<=2*cnt; j++)
                node[j] = node[j-cnt]+2*PI;//[1,cnt]是在-PI到PI,判定的時候要求差值小於PI,所以+2*PI,變成了[PI,3PI],這樣邊界就接上了

            int res = CNT(PI/2);
            ans += res;
            notans += CNT(PI)-res;
        }
        cout<<(ans-2*notans)/3<<endl;
    }
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章