bzoj1052: [HAOI2007]覆盖问题(二分+构造)

  貌似又写出了常数挺优(至少不劣)的代码>v< 930+人AC #49

  写了个O(nlogn)貌似比一些人O(n)还快2333333

  这题还是先二分答案,check比较麻烦

  显然正方形一定以最左上或最右上或最左下或最右下的点为端点来盖,盖了一个之后再拿一个枚举剩下的点作为四个端点来盖,最后一个直接判断剩下的点能不能一次性盖就好了

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio> 
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn=20010,inf=1e9;
typedef int poi[maxn];
poi x,y;
int n,m,l,r,mid,mxx,mxy,mnx,mny;
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
    k*=f;
}
void getmax(poi x,poi y,int tot,int &mxx,int &mxy,int &mnx,int &mny)
{
    mxx=mxy=-inf;mnx=mny=inf;
    for(int i=1;i<=tot;i++)
    {
        mxx=max(mxx,x[i]);mnx=min(mnx,x[i]);
        mxy=max(mxy,y[i]);mny=min(mny,y[i]);
    }
}
bool check(poi x,poi y,int tot,int dep)
{
    int mxx,mxy,mnx,mny,tot2;
    if(dep>2)
    {
        getmax(x,y,tot,mxx,mxy,mnx,mny);
        return max(mxx-mnx,mxy-mny)<=mid;
    }
    getmax(x,y,tot,mxx,mxy,mnx,mny);
    tot2=0;poi x2,y2;
    for(int i=1;i<=tot;i++)
    if(x[i]>mnx+mid||y[i]<mxy-mid)x2[++tot2]=x[i],y2[tot2]=y[i];
    if(check(x2,y2,tot2,dep+1))return 1;    
    tot2=0;
    for(int i=1;i<=tot;i++)
    if(x[i]<mxx-mid||y[i]<mxy-mid)x2[++tot2]=x[i],y2[tot2]=y[i];
    if(check(x2,y2,tot2,dep+1))return 1;
    tot2=0;
    for(int i=1;i<=tot;i++)
    if(x[i]>mnx+mid||y[i]>mny+mid)x2[++tot2]=x[i],y2[tot2]=y[i];
    if(check(x2,y2,tot2,dep+1))return 1;
    tot2=0;
    for(int i=1;i<=tot;i++)
    if(x[i]<mxx-mid||y[i]>mny+mid)x2[++tot2]=x[i],y2[tot2]=y[i];
    if(check(x2,y2,tot2,dep+1))return 1;
    return 0;
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++)read(x[i]),read(y[i]);
    getmax(x,y,n,mxx,mxy,mnx,mny);
    l=1;r=max(mxx-mnx,mxy-mny);
    while(l<r)
    {
        mid=(l+r)>>1;
        if(check(x,y,n,1))r=mid;
        else l=mid+1;
    }
    printf("%d\n",l);
    return 0;
}
View Code
posted @ 2017-09-02 15:48  Sakits  阅读(79)  评论(0编辑  收藏