BZOJ1913: 信号覆盖 题解

非常难的计算几何题,我认为几乎不可做
我们考虑每四个点组成的四边形,如果是凹四边形,那么四个点中每三个构成的四个园中只有一个会包含第四个点,所以贡献是1,如果是凸四边形,则有两个,贡献是2
(注:这幅图片来自csdn“我是傻叉”的博客)
注:这幅图片来自csdn“我是傻叉"的博客
这样 ans=Num×2+NumC3n() a n s = N u m 凸 四 边 形 × 2 + N u m 凹 四 边 形 C n 3 ( 圆 的 总 个 数 )
考虑到 Num+Num=C4n N u m 凸 四 边 形 + N u m 凹 四 边 形 = C n 4 ,所以只要算凹四边形的个数就可以了
凹四边形的实质是有一个点被其他三个点所形成的三角形覆盖
我们枚举被覆盖的点i,然后计算有多少个三角形覆盖这个点
注意到 Num=Num+Num=C4n1 N u m 合 法 的 三 角 形 = N u m 覆 盖 当 前 点 的 三 角 形 + N u m 不 覆 盖 当 前 点 的 三 角 形 = C n − 1 4 ,所以我们只要算不覆盖当前点的三角形数就可以了
我们考虑把所有的点按照极坐标排序,也就是以这个点与当前点连线作为终边的角的大小排序
我们再枚举一个点j,然后逆时针方向找到最远的点pt,使得pt与j的夹角小于180度,那么j+1~pt的店当中任取两个与j构成的三角形都不包含i
然后我们发现随着j的移动,pt的移动是单调的,所以可以利用two pointers之类的思想转一圈
于是总复杂度 O(n2logn) O ( n 2 l o g n ) logn l o g n 来自排序

*这道题卡精度,卡常

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const LL MOD=1e9+7;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-15;
const long double pi=acos(-1);

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

int n;
Pair a[2048];
struct node
{
    int x,y;
    long double ang;
}b[4048];int tot;
int cmpx,cmpy;

inline int calc_region(int x,int y,int xx,int yy)
{
    int dx=xx-x,dy=yy-y;
    if (dx>0 && dy>=0) return 1;
    if (dx<=0 && dy>0) return 2;
    if (dx<0 && dy<=0) return 3;
    if (dx>=0 && dy<0) return 4;
}   

inline long double calc_angle(int x,int y,int xx,int yy)
{
    int pt=calc_region(x,y,xx,yy);
    if (x==xx) return (pt==2?90:270);
    if (y==yy) return (pt==1?0:180);
    long double k=(long double)(y-yy)/(x-xx);
    long double res=atan(k)/pi*180;
    if (pt==1) return res;
    if (pt==2) return res+180;
    if (pt==3) return res+180;
    if (pt==4) return res+360;
}

inline bool cmp(node x,node y)
{
    return y.ang-x.ang>eps;
}

inline long double judge(int ind1,int ind2)
{
    return (b[ind1].ang-b[ind2].ang>eps?b[ind1].ang-b[ind2].ang:b[ind1].ang-b[ind2].ang+360);
}

inline LL C(int x,int y)
{
    if (x<y) return 0;
    LL res=1;int i;
    for (i=x;i>=x-y+1;i--) res*=i;
    for (i=y;i;i--) res/=i;
    return res;
}

int main ()
{
    int i,j;n=getint();
    for (i=1;i<=n;i++) a[i].x=getint(),a[i].y=getint();
    long double ans=0;
    for (i=1;i<=n;i++)
    {
        cmpx=a[i].x;cmpy=a[i].y;tot=0;
        for (j=1;j<=n;j++)
        {
            if (i==j) continue;
            b[++tot]=node{a[j].x,a[j].y,calc_angle(cmpx,cmpy,a[j].x,a[j].y)};
        }
        sort(b+1,b+tot+1,cmp);
        for (j=tot+1;j<=tot*2;j++) b[j]=b[j-tot];
        int pt=1;LL cnt=0;
        for (j=1;j<=tot;j++)
        {
            pt=max(pt,j+1);
            while (judge(pt,j)<180 && pt<j+tot) pt++;pt--;
            cnt+=C(pt-j,2);
        }
        cnt=C(n-1,3)-cnt;ans+=cnt;
    }
    ans=ans+(C(n,4)-ans)*2;ans/=C(n,3);ans+=3;
    printf("%.6Lf\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值