bzoj4617: [Wf2016]Spin Doctor

Description

大选要到了,受候选人X的要求,你调查了n个人,并记录了每个人的3个信息:
ai--他们能记忆π的多少位
bi--他们的头发数量
ci--他们是否会给候选人X投票
你需要找到某个公式使这些结果看起来有意义。你要选择2个实数S和T,将所有调查结果按ai*S+bi*T排序。如果ci
为true的人聚集在了一起,你会觉得这个排序看起来不错。更准确地说,如果j和k分别是第一个和最后一个ci为tr
ue的人的下标,你想要最小化k-j+1。注意有些S和T会让排序时出现相等的情况,这时你应该假设最坏情况发生,
即排序使得k-j+1最大。

Input

第一行一个数n(1 ≤ n ≤ 250000)为被调查的人数。
接下来每行描述一个人的ai(0 ≤ ai ≤ 2000000)、bi(0 ≤ bi ≤ 2000000)、ci
ci是一个0/1变量。保证至少有一个人投了X的票(即至少有一个ci为true)

Output

对于所有可能的实数对(S,T),输出最小的k-j+1。

求出c=1的点的凸包,选出的S,T会使答案为一对包含了凸包的平行线间(含线上)的最小点数

当凸包只有一点时,若这个点不和其余c=1的点重合则答案为1,否则最坏情况下所有与凸包重合的点都被记入答案

当凸包上只有两点时,凸包为一条线段,线段上点数为所求

否则让平行线绕凸包类似旋转卡壳地扫描180度,对每个c=0的点,二分求出这个点进入和离开平行线时平行线对应的角度,得到每个点的出现区间,可以排序计算答案

#include<cstdio>
#include<algorithm>
#include<cmath>
char buf[10000007],*ptr=buf-1;
typedef long double ld;
typedef long long i64;
int _(){
    int x=0,f=1,c=*++ptr;
    while(c<48)c=*++ptr;
    while(c>47)x=x*10+c-48,c=*++ptr;
    return x*f;
}
int abs(int x){return x>0?x:-x;}
struct pos{
    int x,y;
    int abs(){return (x>0?x:-x)+(y>0?y:-y);}
    void fix(){if(y<0||y==0&&x<0)x=-x,y=-y;}
}ps1[250007],ps2[250007],ps[500007];
bool operator<(pos a,pos b){return a.y!=b.y?a.y<b.y:a.x<b.x;}
bool operator==(pos a,pos b){return a.x==b.x&&a.y==b.y;}
pos operator+(pos a,pos b){return (pos){a.x+b.x,a.y+b.y};}
pos operator-(pos a,pos b){return (pos){a.x-b.x,a.y-b.y};}
i64 operator*(pos a,pos b){return i64(a.x)*b.y-i64(a.y)*b.x;}
i64 dot(pos a,pos b){return i64(a.x)*b.x+i64(a.y)*b.y;}
bool cmp(pos a,pos b){
    i64 x=a*b;
    return x?x>0:a.abs()<b.abs();
}
int p1=0,p2=0,pp=0,n,ans=0;
ld as[250007];
const ld pi=3.1415926535897932384626433832795l,_2pi=pi*2;
void fix(ld&x,ld m){
    while(x>=m)x-=m;
    while(x<0)x+=m;
}
struct ev{
    pos a;
    int t;
}es[500007];
bool operator<(ev a,ev b){
    return a.a*b.a>0;
}
int s0=0,ep=0;
int main(){
    fread(buf,1,sizeof(buf),stdin);
    n=_();
    for(int i=0,x,y,c;i<n;++i){
        x=_();y=_();c=_();
        if(c)ps1[p1++]=(pos){x,y};
        else ps2[p2++]=(pos){x,y};
    }
    int _p1=p1;
    ans=p1;
    std::sort(ps1,ps1+p1);
    p1=std::unique(ps1,ps1+p1)-ps1;
    std::sort(ps2,ps2+p2);
    pos p0=ps1[0];
    for(int i=1;i<p1;++i)ps1[i]=ps1[i]-p0;
    std::sort(ps1+1,ps1+p1,cmp);
    ps[pp++]=(pos){0,0};
    for(int i=1;i<p1;++i){
        while(pp>=2&&(ps[pp-2]-ps[pp-1])*(ps1[i]-ps[pp-1])>=0)--pp;
        ps[pp++]=ps1[i];
    }
    for(int i=0;i<pp;++i)ps[i]=ps[i]+p0;
    if(pp==1){
        if(_p1>1)for(int i=0;i<p2;++i)if(ps2[i]==ps[0])++ans;
        return printf("%d",ans),0;
    }
    if(pp==2){
        for(int i=0;i<p2;++i)if((ps2[i]-ps[1])*(ps2[i]-ps[0])==0&&dot(ps2[i]-ps[0],ps2[i]-ps[1])<=0)++ans;
        return printf("%d",ans),0;
    }
    ld xs=0,ys=0,a0;
    for(int i=0;i<pp;++i)xs+=ps[i].x,ys+=ps[i].y,ps[pp+i]=ps[i];
    xs/=pp,ys/=pp;
    ps[pp*2]=ps[0];
    ps[pp*2+1]=ps[1];
    for(int i=0;i<pp;++i)as[i]=std::atan2(ps[i].y-ys,ps[i].x-xs);
    a0=as[0];
    for(int i=0;i<pp;++i)fix(as[i]-=a0,_2pi);
    for(int i=0;i<p2;++i){
        pos w=ps2[i];
        ld a=std::atan2(w.y-ys,w.x-xs);
        fix(a-=a0,_2pi);
        int p=std::upper_bound(as,as+pp,a)-as;
        if((ps[p-1]-w)*(ps[p]-w)>=0){
            ++ans;
            continue;
        }
        ld b=a+pi;
        fix(b,_2pi);
        int p2=std::upper_bound(as,as+pp,b)-as;
        int L=p,R=p2-1,M;
        if(L>R)R+=pp;
        while(L<R){
            M=L+R>>1;
            if((ps[M+1]-w)*(ps[M]-w)>0)L=M+1;
            else R=M;
        }
        pos _l=ps[L]-w;
        _l.fix();
        L=p2;R=p-1;
        if(L>R)R+=pp;
        while(L<R){
            M=L+R>>1;
            if((ps[M+1]-w)*(ps[M]-w)<0)L=M+1;
            else R=M;
        }
        pos _r=ps[L]-w;
        _r.fix();
        es[ep++]=(ev){_l,1},es[ep++]=(ev){_r,-1};
        if(_l*_r<0)++s0;
    }
    std::sort(es,es+ep);
    int s1=s0;
    for(int i=0,j=0;i<ep;){
        for(;j<ep&&es[i].a*es[j].a==0;++j);
        for(;i<j;++i)s0+=es[i].t;
        if(s0<s1)s1=s0;
    }
    printf("%d",ans+s1);
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/6208980.html