• 【2022国赛模拟】多边形——计算几何、二分答案、倍增


    好题无链接

    题目描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    补充说明:题目虽然说的是凸多边形,但是它其实可以不封闭。也就是说,你可以看成是 m m m 个半平面的交。点到边的距离可以看成到线段,也可以看成到直线,其实无所谓。

    题解

    大家都知道落榜美术生的梗吧

    为什么说看成到线段或直线的距离无所谓呢,是因为不管哪一种距离,每条边到原点的距离最好都相等,否则一定不优。有了这个结论,我们发现原点到直线的垂线一定交于线段上。

    首先明白答案具有单调性,然后就可以二分答案了。另外还有一个单调性,即 m m m 越大越优。

    考虑怎么进行 c h e c k \rm check check:首先对于一个可行的解,我们可以把每一条直线往一个方向旋转,直到撞到点上。容易证明任何可行解的每条边总可以调整到与点相交,这样一来需要考虑的直线就只有 n n n 条了。
    在这里插入图片描述
    考虑一个暴力做法,我们枚举一条直线作为起点,然后旋转扫描线,每次顺时针(或逆时针)贪心地找到第一条满足没有节点出现在两直线中间范围内的直线作为下一条。(如上图,假设当前直线为 a a a,那么 b b b 是要找的下一条直线, c c c d d d 都不是)
    直到总共找到 m + 1 m+1 m+1 条直线(包括起点),然后判断扫描线有没有扫过一圈即可。

    直接做是 O ( n 2 log ⁡ ϵ − 1 ) O(n^2\log \epsilon^{-1}) O(n2logϵ1) 的,所以我们双指针预处理一下每条直线对应的下一条直线,然后倍增即可。

    总复杂度 O ( n log ⁡ n log ⁡ ϵ − 1 ) O(n\log n\log \epsilon^{-1}) O(nlognlogϵ1)

    代码

    #include<bits/stdc++.h>//JZM yyds!!
    #define ll long long
    #define lll __int128
    #define uns unsigned
    #define fi first
    #define se second
    #define IF (it->fi)
    #define IS (it->se)
    #define END putchar('\n')
    #define lowbit(x) ((x)&-(x))
    #define inline jzmyyds
    using namespace std;
    const int MAXN=1e5+5;
    const ll INF=1e17;
    ll read(){
    	ll x=0;bool f=1;char s=getchar();
    	while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
    	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
    	return f?x:-x;
    }
    int ptf[50],lpt;
    void print(ll x,char c='\n'){
    	if(x<0)putchar('-'),x=-x;
    	ptf[lpt=1]=x%10;
    	while(x>9)x/=10,ptf[++lpt]=x%10;
    	while(lpt>0)putchar(ptf[lpt--]^48);
    	if(c>0)putchar(c);
    }
    using pdd=pair<double,double>;
    const double PI=acos(-1),eps=1e-7;
    int n,m,sr[MAXN],k;
    pdd tran(const pdd&a){
    	pdd b;
    	b.se=sqrt(a.fi*a.fi+a.se*a.se),b.fi=acos(a.fi/b.se);
    	if(a.se<0)b.fi=PI*2-b.fi;
    	return b;
    }
    double dis(const pdd&a,const pdd&b){
    	pdd c(a.fi-b.fi,a.se-b.se);
    	return sqrt(c.fi*c.fi+c.se*c.se);
    }
    pdd pa[MAXN],a[MAXN];
    double b[MAXN],ch;
    double F(double w){
    	if(w<0)w+=PI*2;
    	if(w>PI*2)w-=PI*2;
    	return min(w,PI*2-w);
    }
    int jp[MAXN][25];
    double jb[MAXN][25];
    bool inl(double y,double r,int x){
    	double ck=F(a[x].fi-y);
    	return ck*2<PI&&a[x].se*cos(ck)>=r-eps;
    }
    bool check(const double&r){
    	for(int i=1;i<=n;i++){
    		b[i]=a[i].fi+acos(r/a[i].se);
    		while(b[i]<0)b[i]+=PI*2;
    		while(b[i]>=PI*2)b[i]-=PI*2;
    		sr[i]=i;
    	}
    	sort(sr+1,sr+1+n,[](int x,int y){return b[x]<b[y];});
    	for(int i=1,j=1;i<=n;i++){
    		int x=sr[i];
    		if(i==j)j=(j==n?1:j+1);
    		while(j!=i&&inl(b[x],r,sr[j]))j=(j==n?1:j+1);
    		jp[i][0]=j,jb[i][0]=b[sr[j]]-b[x];
    		if(jb[i][0]<eps)jb[i][0]+=PI*2;
    	}
    	for(int j=1;j<=18;j++)for(int i=1;i<=n;i++)
    		jp[i][j]=jp[jp[i][j-1]][j-1],jb[i][j]=jb[i][j-1]+jb[jp[i][j-1]][j-1];
    	for(int i=1;i<=n;i++){
    		int x=i;double s=0;
    		for(int j=18;j>=0;j--)if((m>>j)&1)s+=jb[x][j],x=jp[x][j];
    		if(s>PI*2-eps)return 1;
    	}
    	return 0;
    }
    const bool PF=0;
    int main()
    {
    	freopen("polygon.in","r",stdin);
    	freopen("polygon.out","w",stdout);
    	n=read(),m=read(),k=1,ch=INF;
    	for(int i=1;i<=n;i++){
    		int x=read(),y=read();
    		if(x==0&&y==0)return printf("%.9f\n",0.0),0;
    		a[i]=tran(pa[i]=pdd(x,y)),ch=min(ch,a[i].se);
    	}
    	if(m>=n||PF)return printf("%.9f\n",ch),0;
    	double l=0,r=ch,mid;
    	for(int NND=30;NND--;){
    		mid=(l+r)/2;
    		if(check(mid))l=mid;
    		else r=mid;
    	}
    	printf("%.9f\n",mid);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
  • 相关阅读:
    LVS 调度器 nat和DR模式
    二叉树最近公共祖先
    Python大语言模型实战-利用MetaGPT框架自动开发一个游戏软件(附完整教程)
    postgres-operator 原理解析- 章节 II 减少failover次数
    Ubuntu server 24 (Linux) sudo 免输密码
    如何准确且可解释地评估大模型量化效果?
    虚证、实证如何鉴别?
    博客园主题美化中BUG修复方法
    整点猛料!啃完阿里最新版Java面试八股文,大厂面试轻松搞定,拿下offer不是事儿!(金九银十同样适用)
    Linux安全--iptables详解
  • 原文地址:https://blog.csdn.net/weixin_43960287/article/details/125628261