【题目】题目链接

time limit per test
3 seconds
memory limit per test
1024 megabytes
input
standard input
output
standard output

Kiwon's favorite video game is now holding a new year event to motivate the users! The game is about building and defending a castle, which led Kiwon to think about the following puzzle.

In a 2-dimension plane, you have a set p is strictly inside a quadrilateral).

Kiwon is interested in the number of p. Note that, if a single subset can be connected in more than one way to enclose a point, it is counted only once.

Let p∈s.

Input

The first line contains a single integer 5≤n≤2500).

In the next −109≤xi,yi≤109) denoting the position of points are given.

It is guaranteed that all points are distinct, and there are no three collinear points.

Output

Print the sum of p∈s.

Examples
input
5
-1 0
1 0
-10 -1
10 -1
0 3
output
2
input
8
0 1
1 2
2 2
1 3
0 -1
-1 -2
-2 -2
-1 -3
output
40
input
10
588634631 265299215
-257682751 342279997
527377039 82412729
145077145 702473706
276067232 912883502
822614418 -514698233
280281434 -41461635
65985059 -827653144
188538640 592896147
-857422304 -529223472
output
213


【题意】
求对每个点x,f(x)有多少四边形能把这个点包在内;求所有点f(x)的和。
【题解】
发现找几个四边形是很难的,反着想:全部的不包括当前点的四边形为 n*C(n-1,4)。
取当前点P0为原点,每个点与它连线,枚举除它外的另一个点P1,发现与P0/P1选在同一侧的3个点的四边形肯定是不满足的,把这些四边形去掉
找与当前点同一侧的时候,可以利用atan2(y,x)函数,求(x,y)点与原点连线对x轴正方向的角度,取值为[-π,π].相差π内的在同一侧。(注意将负的值加上2π)
可以把点从小到大排序,然后二分查找(注意循环枚举每一个点)

-精度问题
π要用 long double const pai=acos(-1.0L);
随手开 long double
[codeforces1284E]New Year and Castle Construction  几何

 


 ac代码

 1 //这个就是如果定下了四边形中的一个点那么,如果剩下三个点都在一边,那么是不可以的情况
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<vector>
 5 #include<cmath>
 6 #define maxn 2505
 7 using namespace std;
 8 typedef long long ll;
 9 const long double pai = acos(-1.0L);//注意1.0后面有个L,这个影响精度的很重要
10 int n;
11 long long int  x[maxn], y[maxn];
12 vector<long double> v;
13 signed main() {
14     scanf("%d",&n);
15     for(int i = 0; i < n; i++) scanf("%lld%lld", &x[i], &y[i]);
16 
17     ll ans = 1ll * n * (n - 1) * (n - 2) * (n - 3) * (n - 4) / 24;//C_n^5,所有情况数
18     for(int i = 0; i < n; i++) {
19         v.clear();
20         for(int j = 0; j < n; j++) if(i != j) v.push_back(atan2(x[j] - x[i], y[j] - y[i]));//放进每个点的角度
21         sort(v.begin(), v.end());//排个序
22         register int now = 0;//用now线性扫描,可以降低复杂度的
23         ll cnt;
24         for(int j = 0; j < n - 1; j++) {
25             while(now < j + n - 1) {//因为平面是环形的,所以用延长一倍的技巧
26                 long double tmp = v[now % (n - 1)] - v[j];//这才是这个点相对点j的实际角度
27                 if(tmp < 0) tmp += (long double)2 * pai;//多转一圈好判定
28                 if(tmp < pai) now++;
29                 else break;//大于π了明显不合法了
30             }
31             cnt = (now - j - 1);//这里的边界手枚一下就很好理解的
32             ans -= cnt * (cnt - 1) * (cnt - 2) / 6;//cnt一定要开Long long!!这很重要  c n 3
33         }
34     }
35     printf("%lld\n", ans);
36     return 0;
37 }

 

 

没有ac的代码,然而我看不出是哪里的精度问题

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int const maxn=2550;
 4 long double const pai=acos(-1.0L);//这个地方π一定要这样求!否则会出精度问题!
 5 typedef long long ll;
 6 int n;
 7 ll ans;
 8 ll x[maxn],y[maxn];
 9 long double ang[maxn];
10 ll com(ll nn,ll mm){
11     if(mm>nn)return 0;
12     ll ans2=1ll;
13     for(ll i=nn-mm+1;i<=nn;i++)ans2*=i;
14     for(ll i=2;i<=mm;i++)ans2/=i;
15     return ans2;
16 }
17 ll binary(int index){
18     ll l=index+1,r=index+n-2,ans1=0,mid;
19     while(l<=r){
20         mid=(l+r)>>1;
21         if(ang[mid]-ang[index]<=pai)l=mid+1,ans1=mid;
22         else r=mid-1;
23     }
24     if(ans1&&ans1-index>2)return ans1-index;
25     else return 0;
26 }
27 int main(){
28     scanf("%d",&n);
29     for(int i=1;i<=n;i++){
30         scanf("%lld%lld",&x[i],&y[i]);
31     }
32     ans=1ll*n*(n-1)*(n-2)*(n-3)*(n-4)/24;
33     //printf("%lf  %lf  %lf  \n",atan2(-1,0),atan2(2,0),atan2(0,-3));
34     for(int i=1;i<=n;i++){
35         int tot=0;
36         for(int j=1;j<=n;j++)if(j!=i){
37             ang[++tot]=atan2(y[j]-y[i],x[j]-x[i]);
38             if(ang[tot]<0.0)ang[tot]+=2*pai;
39         }
40         sort(ang+1,ang+n);
41         for(int j=1;j<n;j++)ang[j+n-1]=ang[j]+2*pai;
42         
43         for(int j=1;j<n;j++){
44             ans-=com(binary(j),3);
45         }
46     }
47     printf("%lld\n",ans);
48     return 0;
49 }

 


 

 

 


 

 

相关文章:

  • 2021-12-13
  • 2022-01-14
  • 2022-01-11
  • 2022-01-03
  • 2021-05-30
  • 2021-12-01
  • 2021-11-16
猜你喜欢
  • 2022-01-03
  • 2021-06-04
  • 2021-10-26
  • 2022-02-05
  • 2021-06-20
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案