P4385 [COCI2009]Dvapravca

首先特判掉蓝点数量\(<2\)的情况。没有蓝点答案就是\(n\),有一个蓝点可以枚举一个红点,选择过这个蓝点和红点的一条线和在无穷远处的平行线(即这条线对应的两个半平面)。

这里认为过一个点是与这个点无限接近,红点的话认为红点在平行线中,蓝点不在平行线中

构造方案的时候想象两个阶段:

  • 如果有一条线不过蓝点,可以继续向外扩张直到过蓝点为止,现在两条平行线固定过两个蓝点
  • 如果没有平行线过红点,可以旋转这两条平行线知道一个平行线过红点为止。这个过程不会损失红点,而且可能加入新的红点。

所以结论是:两条平行线肯定分别过两个蓝点,而且还有一条平行线过一个红点。

先枚举一个蓝点和一个红点,一条线过这两个点;然后找到在两个方向距离这条线最近的蓝点,直接算红点数量即可。

复杂度\(O(n^3)\)

直接做肯定过不去,所以先把整张图随机旋转,然后按照x坐标排序。

时间的正确性请咨询@Leo______ 。

#include<bits/stdc++.h>
#define il inline
#define vd void
il int gi(){
    int x=0,f=0;char ch=getchar();
    while(!isdigit(ch))f^=ch=='-',ch=getchar();
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
struct point{double x,y;}r[1010],b[1010];
il bool operator<(const point&a,const point&b){return a.x<b.x;}
char col;
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    int n=gi(),R=0,B=0;
    srand(time(NULL));
    double v=rand()%1000*0.1+0.1;
    for(int i=1;i<=n;++i){
        int _x=gi(),_y=gi();
        do col=getchar();while(col!='R'&&col!='B');
        if(col=='R')r[++R]=(point){sin(v)*_x-cos(v)*_y,sin(v)*_y-cos(v)*_x};
        else b[++B]=(point){sin(v)*_x-cos(v)*_y,sin(v)*_y-cos(v)*_x};
    }
    std::sort(r+1,r+R+1);
    std::sort(b+1,b+B+1);
    if(!B)return printf("%d\n",n),0;
    int ans=0;
    double kk,bb,dist,dist_up,dist_dn;
    int upans,dnans;
    for(int i=1;i<=B;++i)
        for(int j=1;j<=R;++j){
            kk=1.0*(b[i].y-r[j].y)/(b[i].x-r[j].x),bb=b[i].y-kk*b[i].x;
            dist_up=1e18,dist_dn=1e18;
            for(int k=1;k<=B;++k)
                if(k!=i){
                    dist=kk*b[k].x+bb-b[k].y;
                    if(dist<0){
                        if(-dist<dist_up)dist_up=-dist;
                    }else{
                        if(dist<dist_dn)dist_dn=dist;
                    }
                }
            upans=1,dnans=1;
            for(int k=1;k<=R;++k)
                if(k!=j){
                    dist=kk*r[k].x+bb-r[k].y;
                    if(dist<0){
                        if(-dist<=dist_up+1e-7)++upans;
                    }else{
                        if(dist<=dist_dn+1e-7)++dnans;
                    }
                }
            ans=std::max(ans,std::max(upans,dnans));
        }
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-01-07 17:01  菜狗xzz  阅读(240)  评论(0编辑  收藏  举报