题目
内容
二维平面中有n个点,定义函数 f ( i ) f(i) f(i),剩余n-1个中选取4个点,这4个点组成的四边形严格包含第 i i i个点,这样的方案有 f ( i ) f(i) f(i)种,求 ∑ i = 1 n f ( i ) \sum_{i=1}^nf(i) ∑i=1nf(i)
分析
考虑一下容斥, f ( i ) = f(i)= f(i)=所有的情况-不包含第 i i i个点的情况
所有的情况= C n − 1 4 C_{n-1}^4 Cn−14 (剩余的n-1个点中选4个点)
如何计算不包含第 i i i个点情况?
首先以第 i i i个点为原点进行极角排序,从小到大枚举每一个点,以当前点和原点的连线将剩余n-2个点分为左右两部分. 我们还需要选择三个点,如果这三个点都在同一侧,那么这四个点组成的四边形就不会包含原点.
为了避免重复计算,我们只计算逆时针方向的那部分,也就是在与当前点叉积大于0的所有点中选三个点.
由于我们是从大到小枚举当前点的,而所有叉积的大于0的点一段连续的区域,因此我们把原点和当前点的连线设为边界,另一边界用一个单调指针维护.
因为我们要对每个点为原点的情况都进行一次极角排序,因此复杂度为 O ( n 2 l o g n ) O(n^2logn) O(n2logn)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define debug(x) cerr<<#x<<' '<<x<<'\n'
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
const int maxn=3e3+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const double eps=1e-9;
int sign(long double a) { return a<-eps?-1:a>eps; }
int cmp(long double a,long double b) { return sign(a-b); }
struct P {
long double x,y;
P() {}
P(long double _x,long double _y) : x(_x),y(_y) {}
P operator+(P p) { return {x+p.x,y+p.y}; }
P operator-(P p) { return {x-p.x,y-p.y}; }
P operator*(long double d) { return {x*d,y*d}; }
P operator/(long double d) { return {x/d,y/d}; }
bool operator==(P o) const {
return cmp(x,o.x)==0&&cmp(y,o.y)==0;
}
long double len() {return sqrt(x*x+y*y);}
long double dot(P p) { return x*p.x+y*p.y; }
long double det(P p) { return x*p.y-y*p.x; }
int quad() { return sign(y)==1||(sign(y)==0&&sign(x)>=0); }
};
bool cmp_angle(P a,P b) {
int qa=a.quad(),qb=b.quad();
if(qa==qb) {
return a.det(b)>0;
}
else return qa<qb;
}
P book[maxn],a[maxn];
ll ans;
ll trans(ll x) {
return x*(x-1)*(x-2)/6;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);
int n;
cin>>n;
ans=1ll*(n-1)*(n-2)*(n-3)*(n-4)/24*n;
rep(i,1,n) {
cin>>book[i].x>>book[i].y;
}
rep(i,1,n) {
int num=0;
rep(j,1,n) {
if(i==j) continue;
a[num++]=book[j]-book[i];
}
sort(a,a+num,cmp_angle);
int now=0;
rep(j,0,num-1) {
while(now<=j) now++;
while(now<j+num&&sign(a[j].det(a[now%num]))>0) now++;
ans-=trans(now-j-1);
}
}
cout<<ans<<'\n';
return 0;
}