【POJ 3179】 Corral the Cows

【题目链接】

           http://poj.org/problem?id=3179

【算法】

           首先,我们发现答案是具有单调性的,也就是说,如果边长为C的正方形可以,那么比边长C大的正方形也可以,因此,可以二分答案

           那么,我们怎么检验呢?

           每个点的坐标最大时达到10000,因此,直接二维前缀和显然是会超时的

           考虑将坐标离散化,然后求二维前缀和,由于N<=500,所以离散化后最多也只有1000个点

           检验时,我们枚举正方形的左上角,用二分求出它的右下角,然后,判断正方形内是否有大于C的草量

【代码】

           

#include <algorithm>  
#include <bitset>  
#include <cctype>  
#include <cerrno>  
#include <clocale>  
#include <cmath>  
#include <complex>  
#include <cstdio>  
#include <cstdlib>  
#include <cstring>  
#include <ctime>  
#include <deque>  
#include <exception>  
#include <fstream>  
#include <functional>  
#include <limits>  
#include <list>  
#include <map>  
#include <iomanip>  
#include <ios>  
#include <iosfwd>  
#include <iostream>  
#include <istream>  
#include <ostream>  
#include <queue>  
#include <set>  
#include <sstream>  
#include <stdexcept>  
#include <streambuf>  
#include <string>  
#include <utility>  
#include <vector>  
#include <cwchar>  
#include <cwctype>  
#include <stack>  
#include <limits.h> 
using namespace std;
#define MAXN 510

int C,N,i,j,l,r,mid,ans,tx,ty,len;
int tmp[MAXN<<1],s[MAXN<<1][MAXN<<1],x[MAXN],y[MAXN];

inline int getsum(int xa,int ya,int xb,int yb)
{
        return s[xb][yb] - s[xa-1][yb] - s[xb][ya-1] + s[xa-1][ya-1];
}
inline bool check(int x)
{
        int i,j,tx,ty,pos;
        if (x > tmp[len]) 
    {
        if (s[len][len] >= C) return true;
        else return false;
    }
    pos = upper_bound(tmp+1,tmp+len+1,tmp[len]-x+1) - tmp - 1;
        for (i = 1; i <= pos; i++)
        {
                for (j = 1; j <= pos; j++)
                {
                        tx = upper_bound(tmp+1,tmp+len+1,tmp[i]+x-1) - tmp - 1;
                        ty = upper_bound(tmp+1,tmp+len+1,tmp[j]+x-1) - tmp - 1;
                        if (getsum(i,j,tx,ty) >= C) return true;        
                }        
        }                
        return false;
}

int main() 
{
        
        scanf("%d%d",&C,&N);
        for (i = 1; i <= N; i++)
        {
                scanf("%d%d",&x[i],&y[i]);    
                tmp[++len] = x[i];
                tmp[++len] = y[i];    
        }
        sort(tmp+1,tmp+len+1);
        len = unique(tmp+1,tmp+len+1) - tmp - 1;
        for (i = 1; i <= N; i++)
        {
                tx = lower_bound(tmp+1,tmp+len+1,x[i]) - tmp;
                ty = lower_bound(tmp+1,tmp+len+1,y[i]) - tmp;
                s[tx][ty]++; 
        }
        tmp[++len] = 10001;
        for (i = 1; i <= len; i++)
        {
                for (j = 1; j <= len; j++)
                {
                        s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + s[i][j];
                }
        }
        l = 1; r = 10000;
        while (l <= r)    
        {
                mid = (l + r) >> 1;
                if (check(mid))
                {
                        r = mid - 1;
                        ans = mid;
                } else l = mid + 1;
        }
        printf("%d\n",ans);
         
        return 0;
    
}

 

转载于:https://www.cnblogs.com/evenbao/p/9243183.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值