標籤:
題意簡述:
在一個格點圖中 給定一個凸$n$邊形(每個定點均在格點上),隨機播放其中一些點構成一個子多邊形,
求子多邊形的內部點個數的期望。
----------------------------------------------------------------------------------------------------------------------------------
首先這題是需要知道 皮克定理 這個結論的
我們用 $s$代表多邊形面積 $ans$代表內部點數(即要求的答案)$node$代表邊上的格點
公式即為 $ans=s-\frac{node}{2}+1$
----------------------------------------------------------------------------------------------------------------------------------
然後這題是求期望的 對於期望 我們知道它是滿足分配率的 於是我們可以考慮分別求出$s$和$node$的期望
對於$s$的期望 可以這樣考慮(算貢獻)
每次選出一個子多邊形後 剩餘部分顯然是可以用多個頂點連續的多邊形補成的
我們可以用首碼和維護這個頂點連續的多邊形的面積 然後來算貢獻
公式為$\displaystyle \frac{2^{n-i} -1}{2^n-1-n-C_2^n}*$子多邊形面積
直接求出所有是$O(n^2)$的 然而觀察公式我們可以發現i取較大的數的時候對答案的影響是很小的
綜合考慮題目要求的$10^-9$的相對誤差以及$double$的精度 $i$可以取$min(n,60)$
$node$的求法也是類似的 只要熟悉如何算貢獻就比較容易了 想了很久還不懂的話可以留言
----------------------------------------------------------------------------------------------------------------------------------
這樣我們就可以過掉範例了 然後我們會$ WA 10$
因為$double$不僅僅是精度 還有範圍 大概範圍就是 $(10^{300}~10^{-300})$
這個問題 初次遇見還是很糾結的 多想想後 我們發現可以把公式變形成這樣(上下同時除$2^n$):
$\displaystyle\frac{2^{-i} -1}{1-2^{-n}*(1+n+C_n^2)}*$子多邊形面積
----------------------------------------------------------------------------------------------------------------------------------
差不多就是這些了 第一次寫$div1D$題 還有些小激動呢
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N=1e5+10;double polygon[N],p[N];int x[N],y[N];double s,ans,node,product;int n,lim;double cross(long long x1,long long y1,long long x2,long long y2){ return x1*y2-x2*y1;}int main(){ scanf("%d",&n); lim=min(n,60); p[0]=1; for(int i=0;i<n;++i) { scanf("%d%d",&x[i],&y[i]); p[i+1]=p[i]*0.5; } for(int i=3;i<lim;++i) { product=(p[i]-p[n])/ (1-p[n]*((long long)n*(n-1)/2+n+1)); for(int j=0;j<n;++j) { polygon[j]+=cross(x[(j+i-2)%n]-x[j],y[(j+i-2)%n]-y[j], x[(j+i-1)%n]-x[j],y[(j+i-1)%n]-y[j]); s-=product*polygon[j]; } } for(int i=0;i<n-2;++i) s+=cross(x[i+1]-x[0],y[i+1]-y[0], x[i+2]-x[0],y[i+2]-y[0]); s/=2; for(int i=2;i<=lim;++i) { product=(p[i]-p[n])/ (1-p[n]*((long long)n*(n-1)/2+n+1)); for(int j=0;j<n;++j) node+=product*__gcd(abs(x[(j+i-1)%n]-x[j]), abs(y[(j+i-1)%n]-y[j])); } ans=s-node/2+1; printf("%.10f\n",ans); return 0;}
codeforces 559D Randomizer