题解clj大神有了就不放了
一道非常好的题目,只是调试能死人罢了
注意要点:
1.此时的极角排序必须加上象限的判断不然会出错(重要!)
2.注意每次point数组必须清空而不能复用因为编号乱了
3.以后数组开到原来的4倍左右防止因数组开小而出错
4.使用long long类型可以有效避免精度误差
5.以后碰到这种题我就写一个$O(n^3)$的暴力,因为这题数据很良心是可以过的,而且我考场上几乎100%不能调试成功
下面版本复杂度为$O(n^2logn)$
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=4005; const double eps=1e-17; int n,cnt,ind[N]; double ans; struct Point{ long long x,y; int id; Point(){} Point(long long _x,long long _y){x=_x;y=_y;} friend inline Point operator+(const Point &A,const Point &B){return Point(A.x+B.x,A.y+B.y);} friend inline Point operator-(const Point &A,const Point &B){return Point(A.x-B.x,A.y-B.y);} friend inline long long operator*(const Point &A,const Point &B){return A.x*B.y-A.y*B.x;} friend inline bool operator==(const Point &A,const Point &B){return A.x==B.x && A.y==B.y;} }ChosenPoint,point[N<<1]; inline int Check(Point A){ if(A.x-ChosenPoint.x>0 && A.y-ChosenPoint.y>=0)return 0; if(A.x-ChosenPoint.x<=0 && A.y-ChosenPoint.y>0)return 1; if(A.x-ChosenPoint.x<0 && A.y-ChosenPoint.y<=0)return 2; return 3; } inline int Dist2(const Point &A,const Point &B){return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);} inline bool cmp(const Point &A,const Point &B){int x=Check(A),y=Check(B);if(x!=y)return x<y;return (A-ChosenPoint)*(B-ChosenPoint)>=0;} inline bool OnRight(const Point &A,const Point &B,const Point &C){return (B-A)*(C-A)>=0;} struct Pair_Points{ Point A,B; }poi[N]; int main(){ freopen("1225.in","r",stdin); freopen("1225.out","w",stdout); scanf("%d",&n); if(n<3){puts("0.000000");return 0;} for(int i=1;i<=n;i++)scanf("%lld %lld %lld %lld",&poi[i].A.x,&poi[i].A.y,&poi[i].B.x,&poi[i].B.y); for(int i=1;i<=n;i++){ ChosenPoint=poi[i].A; cnt=0; for(int j=1;j<=n;j++){ if(i==j)continue; point[++cnt]=poi[j].A;point[cnt].id=j;point[++cnt]=poi[j].B;point[cnt].id=j; } sort(point+1,point+cnt+1,cmp); memset(ind,0,sizeof(ind)); int cntx[3]={n-1},pos=1; for(int j=cnt+1;j<=2*cnt;j++)point[j]=point[j-cnt]; for(int j=1;j<=cnt;j++){ while(pos<j+cnt && OnRight(ChosenPoint,point[j],point[pos])){ ind[point[pos].id]++; cntx[ind[point[pos].id]]++; cntx[ind[point[pos].id]-1]--; pos++; } //printf("%d %d %d %d\n", pos, cntx[0], cntx[1], cntx[2]); if(cntx[1]+cntx[2]==n-1){ double afk=0.125; if(ind[point[j].id]==1)afk/=pow(2,cntx[1]-1); else afk/=pow(2,cntx[1]); ans+=afk*(ChosenPoint*point[j]); } ind[point[j].id]--; cntx[ind[point[j].id]]++; cntx[ind[point[j].id]+1]--; } } for(int i=1;i<=n;i++){ ChosenPoint=poi[i].B; cnt=0; for(int j=1;j<=n;j++){ if(i==j)continue; point[++cnt]=poi[j].A;point[cnt].id=j;point[++cnt]=poi[j].B;point[cnt].id=j; } sort(point+1,point+cnt+1,cmp); memset(ind,0,sizeof(ind)); int cntx[3]={n-1},pos=1; for(int j=cnt+1;j<=2*cnt;j++)point[j]=point[j-cnt]; for(int j=1;j<=cnt;j++){ while(pos<j+cnt && OnRight(ChosenPoint,point[j],point[pos])){ ind[point[pos].id]++; cntx[ind[point[pos].id]]++; cntx[ind[point[pos].id]-1]--; pos++; } //printf("%d %d %d %d\n", pos, cntx[0], cntx[1], cntx[2]); if(cntx[1]+cntx[2]==n-1){ double afk=0.125; if(ind[point[j].id]==1)afk/=pow(2,cntx[1]-1); else afk/=pow(2,cntx[1]); ans+=afk*(ChosenPoint*point[j]); } ind[point[j].id]--; cntx[ind[point[j].id]]++; cntx[ind[point[j].id]+1]--; } } printf("%.17lf\n",ans); return 0; }