HDU 6882 Divide and Conquer(二分)

题面

\(使用两条相交直线平分n个点,使得每块区域都包含\frac{n}{4}个点,保证n\%4\equiv0\)

Solution

首先我们可以明确此题一定是有解的,所以我们可以首先固定一条平分线再去寻找第二条平分线,那么第一条平分线我们可以通过将所有点按照\(x,y\)排序,选取中间\([\frac{n}{2}-1]和[\frac{n}{2}]\)两个点,选取一条斜率接近\(\frac{\pi}{2}\)的直线平分即可,那么第二条线的斜率就是在\([-\frac{\pi}{2},\frac{\pi}{2}]\)之间,我们需要找到这样一条直线满足和第一条直线恰好平分一侧的\(\frac{n}{2}\)个点,我们可以发现这条直线的斜率是可以进行二分的,我们可以将每个点按照此斜率投射到之前第一条直线上,排序后直接可以遍历记录左侧点和右侧点的个数,如果一侧点不够\(\frac{n}{2}另一侧点多于\frac{n}{2}\)个点,那么我们可以将斜率往点少的一侧倾斜即可,最后可以得到恰好平分的斜率以及那个平分位置前一个点,那么直接将一条直接经过该点并平行上一丢丢距离就可以完成构造,总体复杂度\({O(nlog^2n)}\)

//      ——By DD_BOND

//#include<bits/stdc++.h>
//#include<unordered_map>
//#include<unordered_set>
#include<functional>
#include<algorithm>
#include<iostream>
//#include<ext/rope>
#include<iomanip>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<cstddef>
#include<cstdio>
#include<memory>
#include<vector>
#include<cctype>
#include<string>
#include<cmath>
#include<queue>
#include<deque>
#include<ctime>
#include<stack>
#include<map>
#include<set>

#define fi first
#define se second
#define pb push_back
#define MP make_pair

//#pragma GCC optimize(3)
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

using namespace std;

typedef double db;
typedef long long ll;
typedef pair<db,db> Pd;
typedef pair<int,int> P;
typedef pair<ll,ll> Pll;

const db eps=1e-8;
const int MAXN=1e3+10;
const db pi=acos(-1.0);
const ll INF=0x3f3f3f3f3f3f3f3f;

inline int dcmp(db x){
    if(fabs(x)<eps) return 0;
    return (x>0? 1: -1);
}

inline db Sqrt(db x){
    return x>0? sqrt(x): 0;
}

inline db sqr(db x){ return x*x; }

struct Point{
    db x,y;
    Point(){ x=0,y=0; }
    Point(db _x,db _y):x(_x),y(_y){}
    void input(){
        double _x,_y;
        scanf("%lf%lf",&_x,&_y); 
        x=_x,y=_y;
    }
    bool operator <(const Point &b)const{
        return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x);
    }
    db operator ^(const Point &b)const{     //叉积 
        return x*b.y-y*b.x;
    }
    db operator *(const Point &b)const{     //点积
        return x*b.x+y*b.y;
    }
    Point operator +(const Point &b)const{
        return Point(x+b.x,y+b.y);
    }
    Point operator -(const Point &b)const{
        return Point(x-b.x,y-b.y);
    }
    Point operator *(db a){
        return Point(x*a,y*a);
    }
    Point operator /(db a){
        return Point(x/a,y/a);
    }
};

inline db cross(Point a,Point b){   //叉积        
    return a.x*b.y-a.y*b.x;
}

inline db dot(Point a,Point b){ //点积        
    return a.x*b.x+a.y*b.y;
}

struct Line{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
    db polar(){ //极角
        return atan2(e.y-s.y,e.x-s.x);   //返回与x轴正向夹角(-pi~pi]
    }
};

Point line_intersection(Line a,Line v){ //直线交点  调用前确保有交点
    db a1=cross(v.e-v.s,a.s-v.s);
    db a2=cross(v.e-v.s,a.e-v.s);
    return Point((a.s.x*a2-a.e.x*a1)/(a2-a1),(a.s.y*a2-a.e.y*a1)/(a2-a1));
}


Line l1,l2;
Point point[50010];
pair<db,int>st[50010];

int main(void){
    int t;  scanf("%d",&t);
    while(t--){
        int n;  scanf("%d",&n);
        for(int i=0;i<n;i++)    point[i].input();
        sort(point,point+n);
        if(point[n/2-1].x==point[n/2].x){
            int sum=point[n/2-1].y+point[n/2].y;
            l1=Line(Point(point[n/2].x-1,-9e8+sum/2),Point(point[n/2].x+1,9e8+sum/2+(sum%2)));
        }
        else    l1=Line(Point(point[n/2-1].x,-9e8),Point(point[n/2].x,9e8));
        int las=0;
        db l=l1.polar()-pi+eps,r=l1.polar()-eps,theta=-1;
        for(int t=1;t<=60;t++){
            int f=0;
            db mid=(l+r)/2;
            Point vec(1e6*cos(mid),1e6*sin(mid));
            for(int i=0;i<n;i++)    st[i]={line_intersection(l1,Line(point[i],point[i]+vec)).y,i};
            sort(st,st+n);
            for(int i=0,ls=0,rs=0;i<n;i++){
                if(i){
                    if(dcmp(st[i-1].fi-st[i].fi)==0){
                        if(st[i].se<n/2)    ls++;
                        else                rs++;
                    }
                    else{
                        if(ls==n/4&&rs==n/4){ f=1,las=st[i-1].se,theta=mid; break; }
                        else if(ls>=n/4){ l=mid; break; }
                        else if(rs>=n/4){ r=mid; break; }
                        if(st[i].se<n/2)    ls++;
                        else                rs++;
                    }
                }
                else{
                    if(st[i].se<n/2)    ls++;
                    else                rs++;
                }
            }
            if(f)   break;
        }
        l2=Line(point[las]+Point(9e8*cos(theta),9e8*sin(theta)),point[las]-Point(9e8*cos(theta),9e8*sin(theta)));
        printf("%d %d %d %d\n",(int)round(l1.s.x),(int)round(l1.s.y),(int)round(l1.e.x),(int)round(l1.e.y));
        printf("%d %d %d %d\n",(int)round(l2.s.x),(int)round(l2.s.y+0.9999),(int)round(l2.e.x),(int)round(l2.e.y+0.999));
    }
    return 0;
}
posted @ 2020-08-21 13:56  DD_BOND  阅读(457)  评论(0编辑  收藏  举报