• 【JZOJ6388】小w的作业


    description


    analysis

    • 二分一个角度,首先假设该弧度角( heta in[{pi over 2},pi]),要找的直线斜率(kin(-∞, an heta])

    • 要找这种直线,两个点((x_i,y_i),(x_j,y_j))构成一条直线,先钦定(x_i≤x_j)

    • 直线斜率({{y_j-y_i}over{x_j-x_i}}≤ an heta),转化后变成(y_j-x_j an heta≤y_i-x_i an heta)

    • 因为两边分别只和(i,j)有关,可以把(y_k-x_k an heta)记做(yy_k)((x_i,y_i))映射到((x_i,yy_i))

    • 此时就是要求有多少对点(x_i≤x_j,yy_i≥yy_j),二维偏序,用树状数组解决

    • 这种情况少计算了斜率为正的直线条数,需要把算少的这部分加起来

    • 那么对于( hetain[0,{pi over 2})),计算斜率小于( an heta)的直线条数过程是完全一样的

    • 这种情况又多计算了斜率为负的直线条数,需要把算多的这部分减掉

    • 经过一个点有多少条直线斜率为正,就是一个点右上角的点个数;斜率为负就是左上角的点个数

    • 这个可以一开始用两次树状数组求出(sum)右上角点个数和(sum)左上角点个数

    • 由于二分区间不同,这里左上角右上角求的范围有一点点差别,左上角必须严格高于该点,右上角则否

    • 二分的时候判断当前在直线右手边的直线条数是否大于等于比较数,是则(r)右移,否则(l)左移

    • 注意取开闭区间和计算的小细节


    code

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #define eps 1e-10
    #define MAXN 100005
    #define db double 
    #define ll long long
    #define reg register ll
    #define lowbit(x) ((x)&(-x))
    #define pi 3.1415926535897932384626
    #define fo(i,a,b) for (reg i=a;i<=b;++i)
    #define fd(i,a,b) for (reg i=a;i>=b;--i)
    
    using namespace std;
    
    ll tr[MAXN],sum[MAXN];
    ll n,m,tot,summ1,summ2;
    
    struct node
    {
    	ll x,y;
    }a[MAXN];
    struct node1
    {
    	db x;ll y,val;
    }b[MAXN];
    inline ll read()
    {
    	ll x=0,f=1;char ch=getchar();
    	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
    	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    inline bool cmp(node a,node b){return a.x<b.x || (a.x==b.x && a.y>b.y);}
    inline bool cmp1(node1 a,node1 b){return a.x<b.x;}
    inline bool cmp2(node1 a,node1 b){return a.y<b.y;}
    inline void insert(ll x){while (x<=n)++tr[x],x+=lowbit(x);}
    inline ll query(ll x){ll y=0;while (x)y+=tr[x],x-=lowbit(x);return y;}
    inline ll get(ll x,ll y){return query(y)-query(x-1);}
    inline db binary(db m)
    {
    	db l=0,r=pi,mid,tann;
    	while (r-l>eps)
    	{
    		mid=(l+r)/2.0,tann=tan(mid);
    		memset(tr,0,sizeof(tr)),memset(sum,0,sizeof(sum));
    		fo(i,1,n)b[i].x=1.0*(a[i].y-a[i].x*tann),b[i].y=i;
    		sort(b+1,b+n+1,cmp1),tot=0;
    		fo(i,1,n)
    		{
    			b[i].val=++tot;
    			while (i<n && fabs(b[i].x-b[i+1].x)<eps)b[++i].val=tot;
    		}
    		sort(b+1,b+n+1,cmp2);ll total=0;
    		fd(i,n,1)total+=(sum[i]=get(1,b[i].val)),insert(b[i].val);
    		total+=(mid*2>pi?summ1:-summ2);
    		if (total>=m)r=mid;else l=mid;
    	}
    	return r;
    }
    int main()
    {
    	//freopen("T2.in","r",stdin);
    	freopen("line.in","r",stdin);
    	freopen("line.out","w",stdout);
    	n=read(),m=n*(n-1)/2;
    	fo(i,1,n)a[i].x=read(),a[i].y=read();
    	sort(a+1,a+n+1,cmp);
    	fo(i,1,n)b[i].x=a[i].y,b[i].y=i;
    	sort(b+1,b+n+1,cmp1),tot=0;
    	fo(i,1,n)
    	{
    		b[i].val=++tot;
    		while (i<n && b[i].x==b[i+1].x)b[++i].val=tot;
    	}
    	sort(b+1,b+n+1,cmp2);
    	fd(i,n,1)summ1+=get(b[i].val,tot),insert(b[i].val);
    	memset(tr,0,sizeof(tr));
    	sort(a+1,a+n+1,cmp);
    	fo(i,1,n)b[i].x=a[i].y,b[i].y=i;
    	sort(b+1,b+n+1,cmp1),tot=0;
    	fo(i,1,n)
    	{
    		b[i].val=++tot;
    		while (i<n && b[i].x==b[i+1].x)b[++i].val=tot;
    	}
    	sort(b+1,b+n+1,cmp2);
    	fo(i,1,n)summ2+=get(b[i].val+1,tot),insert(b[i].val);
    	printf("%.13lf
    ",m&1?binary((m+1)/2):(binary(m/2)+binary(m/2+1))/2);
    	return 0;
    }
    
  • 相关阅读:
    从ReentrantLock的实现看AQS的原理及应用
    Java 守护线程
    js静态文件编辑器显示操作,但网页显示中文乱码 解决方案
    springmvc 4.3版本集成 Caffeine缓存系统
    chrome浏览器如何设置黑色背景
    电脑型号19 1200 固态SSD
    电脑型号18 1200 固态SSD
    geohash st_distance st_distance_sphere 关系
    Git自动输入账户名密码。明文及SSH私钥2种方式
    一步快速获取 iOS 设备的 UDID
  • 原文地址:https://www.cnblogs.com/horizonwd/p/11746586.html
Copyright © 2020-2023  润新知