zoukankan      html  css  js  c++  java
  • CF607E Cross Sum

    Link
    (O(x,y))
    我们将这道题分为两个部分:首先求出第(m)远的交点到(O)的距离,然后再计算前(m)远的交点到(O)的距离之和。

    一、求第(m)远的交点

    先二分答案(r),接下来就变成了判定是否有(m)个交点在(igcirc(O,r))内。
    注意到在(igcirc)内的交点一定满足生成该交点的两条直线都与(igcirc)相交或相切。
    将所有直线与(igcirc)的交点(相切的算两个)按与(O)点连线的极角排序。
    可以发现两条直线的交点在(igcirc)内的充要条件是两条直线与(igcirc)的交点交错分布。
    那么用BIT简单维护即可。

    二、求前(m)远的交点到(O)的距离之和

    注意到(mle10000000),因此使用链表维护交点,然后(O(m))暴力找出每一个交点即可。
    Tips:
    可能会有一些点到(O)的距离相同,那么我们先将它们都计算,然后再减去多计算的部分即可,可以证明这样的点的个数是(O(n))的。

    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using db=double;
    int read(){int x;scanf("%d",&x);return x;}
    const int N=50007;const db eps=1e-10;
    db x,y,k[N],b[N],ans;int n,c,t[N*2],las[N],L[N*2],R[N*2];
    struct node{db ang;int id;}a[N*2];
    db sqr(db a){return a*a;}
    void add(int p,int v){for(;p<=c;p+=p&-p)t[p]+=v;}
    int ask(int p){int s=0;for(;p;p^=p&-p)s+=t[p];return s;}
    int check(db r)
    {
        db A,B,C,D,X,Y;int s=0;c=0;
        for(int i=1;i<=n;++i)
        {
    	A=sqr(k[i])+1,B=-2*x+2*k[i]*(b[i]-y),C=sqr(x)+sqr(b[i]-y)-sqr(r);
    	if(B*B<=4*A*C) continue;
    	D=sqrt(sqr(B)-4*A*C),A*=2;
    	X=(D-B)/A,Y=k[i]*X+b[i],a[++c]={atan2(Y-y,X-x),i};
    	X=(-D-B)/A,Y=k[i]*X+b[i],a[++c]={atan2(Y-y,X-x),i};
        }
        std::sort(a+1,a+c+1,[](const node&a,const node&b){return a.ang<b.ang;});
        for(int i=1,id;i<=c;++i) las[id=a[i].id]? s+=ask(i)-ask(las[id]),add(las[id],-1),las[id]=0:(add(i,1),las[id]=i);
        return s;
    }
    int pre[100010],nxt[100010],lst;
    db cal(int i,int j)
    {
        db X=(b[j]-b[i])/(k[i]-k[j]),Y=X*k[i]+b[i];
        return sqrt(sqr(X-x)+sqr(Y-y));
    }
    int main()
    {
        db l=0;int m,s=0;
        n=read(),x=read()/1000.0,y=read()/1000.0,m=read();
        for(int i=1;i<=n;++i) k[i]=read()/1000.0,b[i]=read()/1000.0;
        for(db r=1e13,mid,i=100;i>0;--i) check(mid=(l+r)/2)<m? l=mid:r=mid;
        check(l);
        for(int i=1,j=0,p;i<=c;++i)
    	if(las[a[i].id])
    	{
    	    for(p=j;p>las[a[i].id];p=L[p]) ++s,ans+=cal(a[i].id,a[p].id);
    	    R[L[p]]=R[p],L[R[p]]=L[p];
    	    if(p==j) j=L[j];
    	}
    	else R[j]=i,L[i]=j,j=i,las[a[i].id]=i;
        printf("%.10lf",ans+l*(m-s));
    }
    
  • 相关阅读:
    【MFC】对话框自带滚动条的使用
    【MFC】MFC DLEdit 设计属于自己的编辑框_鼠标悬停
    【MFC】MoveWindow();函数使用详解
    【MFC】SetWindowPos函数使用详解
    模板 key+1
    lazyload 分页加载
    缓慢显示隐藏
    js计算日期的前几天的日期
    判断子元素(or属性)是否存在
    动态加载的数据,hover效果
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12337302.html
Copyright © 2011-2022 走看看