• CF559D Randomizer 题解


    Codeforces
    Luogu

    Description.

    给定一个凸包,随机选一个点数 \(\ge3\) 的点集。
    问选出点集构成凸包内整点数的期望。
    精度 \(10^{-9}\)

    Solution.

    首先,凸包内整点显然想到皮克定理。
    皮克定理是 \(Area=Cnt_{inside}+\frac{Cnt_{edge}}{2}-1\)
    然后如果求凸包内好像牵扯的信息比较多,可以考虑容斥。
    答案就是原凸包内的整点(算边)减去被切掉的凸包内整点(算边)。
    然后被切掉凸包肯定是原凸包上的一段序列。
    于是显然就有一个 \(O(n^2)\) 做法,就考虑枚举新凸包的下一个点。
    可以直接维护,概率是 \(\frac{2^{n-k}-1}{2^n-1-n-n\times(n-1)\div 2}\),其中 \(k\) 表示选点个数。

    但是怎么从 \(O(n^2)\) 优化到更优呢。
    哈哈,我们发现 \(\frac{1}{60}\le 10^{18}\),所以直接枚举后 \(60\) 个点即可,复杂度变成了 \(O\left(n\log\left(\frac{10^9}{10^{-9}}\right)\right)\),直接 A 了!

    Coding.

    点击查看菜瓜代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
    const int N=100005;int n;typedef long double db;
    struct vec
    {
    	int x,y;
    	inline vec operator+(vec b) {return(vec){x+b.x,y+b.y};}
    	inline vec operator-(vec b) {return(vec){x-b.x,y-b.y};}
    	inline ll operator*(vec b) {return 1ll*x*b.y-1ll*y*b.x;}
    	inline int count() {return abs(__gcd(x,y));}
    }a[N];db pw[N];
    inline db gl(int k)
    {
    	if(n>100) return 1.0/pw[k];
    	return (pw[n-k]-1)/(pw[n]-1-n-1.0*n*(n-1)/2);
    }
    int main()
    {
    	read(n);for(int i=1;i<=n;i++) read(a[i].x,a[i].y);
    	pw[0]=1;for(int i=1;i<=100;i++) pw[i]=pw[i-1]*2;
    	ll Cn=0,S=0;for(int i=1;i<=n;i++) S+=a[i]*a[i%n+1],Cn+=(a[i%n+1]-a[i]).count();
    	db del=0;for(int i=1;i<=n;i++)
    	{
    		ll s=a[i]*a[i%n+1],cn=(a[i%n+1]-a[i]).count();
    		for(int k=3,j=(i+1)%n+1;k<=60&&j%n+1!=i;k++,j=j%n+1)
    		{
    			s+=a[(j-2+n)%n+1]*a[j],cn+=(a[j]-a[(j-2+n)%n+1]).count();
    			del+=gl(k)*(s+a[j]*a[i]-cn+(a[i]-a[j]).count())/2.0;
    #ifdef debug
    			printf("gl : %.10Lf\n",gl(k));
    			printf("del : %.10lf\n",(s+a[j]*a[i]-cn+(a[i]-a[j]).count())/2.0);
    #endif
    		}
    	}
    	return printf("%.10Lf\n",(S+2-Cn)/2.0-del),0;
    }
    
  • 相关阅读:
    常用Git代码托管服务分享
    .NET中操作IPicture、IPictureDisp
    Git学习笔记与IntelliJ IDEA整合
    螺旋队列问题
    杂题3道
    .NET 配置文件简单使用
    C++之Effective STL
    不容易理解的 lock 和 merge
    状态模式
    观察者模式
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15191383.html
Copyright © 2020-2023  润新知