主要在这个双指针扫描法上,它的意思是说把左右边界找到,然后在这个区间内的就是符合条件的,(据说比二分优越)
这个开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;
}
}