CodeForces 1284E New Year and Castle Construction 题解
bluewindde · · 题解
观察样例发现,四边形可以不是凸的。
对于非凸四边形
对于凸四边形
改成统计不合法四元子集个数,这相当于统计选出五个点
枚举每条边,它所在的直线将平面分成两半,设两半分别有
用向量积判断点处于哪一半平面,设枚举直线
拆向量积:
先偷点懒:因为不存在三点共线,所以把
然后分类讨论
于是可以求出
时间复杂度
注意分数比大小时也应判断正负号。
#include<iostream>
#include<algorithm>
#include<vector>
#define int long long
using namespace std;
typedef long double ld;
const int o=1e9;
int n;
struct node{
int x,y,id;
friend inline node operator-(const node &x,const node &y){
return {x.x-y.x,x.y-y.y};
}
}a[2505];
static inline int cross(const node &A,const node &B){
return A.x*B.y-A.y*B.x;
}
struct frac{
int p,q;
friend inline bool operator<(const frac &x,const frac &y){
if(x.q*y.q<0)
return x.p*y.q>y.p*x.q;
return x.p*y.q<y.p*x.q;
}
};
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;++i){
cin>>a[i].x>>a[i].y;
a[i].id=i;
}
int ans=n*(n-1)*(n-2)*(n-3)*(n-4)/24; // n * C(n-1, 4)
for(int i=1;i<=n;++i){
vector<frac>v1,v2;
vector<node>ex;
for(int j=1;j<=n;++j){
if(i==j)
continue;
node x=a[j]-a[i];
if(x.y==0)
ex.push_back(x);
else if(x.y>0)
v1.push_back({x.x,x.y});
else
v2.push_back({x.x,x.y});
}
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
for(int j=i+1;j<=n;++j){
node A=a[j]-a[i];
int c1=0,c2=0;
if(A.y==0){
for(int k=1;k<=n;++k){
if(i==k||j==k)
continue;
if(cross(a[k]-a[i],a[j]-a[i])>0)
++c1;
else
++c2;
}
}else{
if(A.y>0){
c1+=v1.end()-upper_bound(v1.begin(),v1.end(),frac{A.x,A.y});
c1+=lower_bound(v2.begin(),v2.end(),frac{A.x,A.y})-v2.begin();
}else{
c1+=lower_bound(v1.begin(),v1.end(),frac{A.x,A.y})-v1.begin();
c1+=v2.end()-upper_bound(v2.begin(),v2.end(),frac{A.x,A.y});
}
for(auto p:ex){
if(p.id==i||p.id==j)
continue;
if(cross(p,a[j]-a[i])>0)
++c1;
}
c2=n-2-c1;
}
// c1=c2=0;
// for(int k=1;k<=n;++k){
// if(i==k||j==k)
// continue;
// if(cross(a[k]-a[i],a[j]-a[i])>0)
// ++c1;
// else
// ++c2;
// }
// C(c1, 3) + C(c2, 3)
ans-=c1*(c1-1)*(c1-2)/6;
ans-=c2*(c2-1)*(c2-2)/6;
}
}
cout<<ans<<endl;
return 0;
}