• 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));
    }
    
  • 相关阅读:
    hdu 4970 树状数组 “改段求段”
    hdu 2242 无向图/求用桥一分为二后使俩个bcc点权值和之差最小并输出 /缩点+2次新图dfs
    hdu3715 2-sat+二分
    hdu 3639 有向图缩点+建反向图+搜索
    hdu 3072 有向图缩点成最小树形图计算最小权
    hdu 3061 hdu 3996 最大权闭合图 最后一斩
    hdu 3879 hdu 3917 构造最大权闭合图 俩经典题
    hdu 4738 无向图缩点断桥 // 细节坑题
    hdu3452 无向树去掉最小的边集使任何叶子与根不连通 / 最小割
    hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12337302.html
Copyright © 2020-2023  润新知