原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round3-I.html
题目传送门 - 2018牛客多校赛第三场 I
题意
在一个给定的三角形内部随机选择 $n$ 个点,问这些点构成的凸包的期望顶点数。
$3leq nleq 10$
题解
首先证明一个结论,对于任意三角形,随机撒 $n$ 个点的期望点数相同。
简单口胡:考虑任意拉扯三角形,三角形内部多边形的凸性都不会改变。
所以,我们只需要随便选择一个三角形,然后随机选点很多次,建出凸包,得到顶点数,然后算一算平均值,就可以得到答案了。
注意随机选点次数至少好几亿吧。
我赛后代码跑了大约 25 分钟才跑出来。
代码1 - 打表
%:pragma GCC optimize("Ofast") %:pragma GCC optimize("inline") #include <bits/stdc++.h> using namespace std; typedef long long LL; const int N=20; int n; struct Point{ int x,y; Point(){} Point(int _x,int _y){ x=_x,y=_y; } }P[N],O; LL cross(Point a,Point b,Point c){ return 1LL*(b.x-a.x)*(c.y-a.y)-1LL*(c.x-a.x)*(b.y-a.y); } int Drand(){ return (int)((((rand()&32767)<<10)+(rand()&1024))&33554431); } LL sqr(int x){ return 1LL*x*x; } LL dis(Point a,Point b){ return sqr(a.x-b.x)+sqr(a.y-b.y); } bool cmp_O(Point a,Point b){ if (a.y==b.y) return a.x<b.x; return a.y<b.y; } bool cmp_Angle(Point a,Point b){ LL c=cross(O,a,b); if (c==0) return dis(O,a)<dis(O,b); return c>0; } int st[N],top; int Convex(){ for (int i=2;i<=n;i++) if (!cmp_O(P[1],P[i])) swap(P[1],P[i]); O=P[1]; sort(P+2,P+n+1,cmp_Angle); top=0; st[++top]=1,st[++top]=2; for (int i=3;i<=n;i++){ while (top>=2&&cross(P[st[top-1]],P[st[top]],P[i])<=0) top--; st[++top]=i; } return top; } int main(){ freopen("list.txt","w",stdout); srand(time(NULL)); for (int i=3;i<=10;i++){ n=i; int tot=200000000,ttt=tot; int ans=0; while (tot--){ for (int i=1;i<=n;i++) while (1){ P[i]=Point(Drand(),Drand()); if (P[i].y<=P[i].x) break; } ans+=Convex(); } printf("%.6lf ",((double)ans)/ttt); } return 0; }
代码2 - AC 代码
#include <bits/stdc++.h> using namespace std; double ans[11]={ 0,0,0, 3.000000, 3.666719, 4.166715, 4.566691, 4.899998, 5.185735, 5.435731, 5.657986 }; int main(){ int n; for (int i=1;i<=7;i++) scanf("%d",&n); printf("%.6lf",ans[n]); return 0; }