【hdu5741】helter skelter

H

看了官方给的提解后恍然大悟,不过其实没必要用凸包,只要枚举即可。


首先想象0,1的字串都各只有一串的情况,则图形为一个完整的矩形。当字串增加,就是多个矩形的叠加。

因此只扫一次是明显不够的,要以每一个0串为起始串枚举下边界,以每一个1串为起始枚举上边界。

但是这样得到的两串数对(x,y)是冗余的,因此需要对得到的数对进行筛选,精简。

即找到如题解中所示的红点,以及绿点这些关键点。(蓝点是没必要去找的,蓝点是两个红点或绿点的交点处的点)

求红点的代码如下:(参考博客 http://blog.csdn.net/techmonster/article/details/52000284)

    sort(lowp,lowp+cl);
    n = 0;

    for(int i = 0,j; i < cl; i = j) {
        //找边界点(红点)
        for(j = i; j < cl && lowp[j].first == lowp[i].first; ++j);           //从i开始,到cl为止的点,如果x坐标相等,j++,越过横坐标相同的点(已排序)
        while(n > 0 && lowp[n-1].second >= lowp[i].second) --n;  //如果纵坐标减小,则更新边界点
        lowp[n++] = lowp[i];
    }
    cl = n;

找到红点及绿点后,只要对点的边界二分搜索即可,在图形范围内则为1,否则为0。

完整代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
using namespace std;

#define MS(x,y) memset(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define MAXN 100005

typedef long long LL;

const int N = (1e6)+10, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;

int n,m,org[1010];
pair<int ,int>lowp[N],upp[N];
char ans[MAXN*5];

void solve() {
    scanf("%d%d",&n,&m);
    for(int i = 0; i < n; ++i) scanf("%d",&org[i]); //org 储存0,1串

    int x,y,cl = 0,cu = 0;
    for(int i = 0; i < n; ++i) {
        //暴力枚举所有边界
        x=y=0;
        for(int j = i; j < n; ++j) {
            if(j%2 == 0) x+=org[j];
            else y+=org[j];
            if((i%2 == 0 && j%2 == 0) ) lowp[cl++] = MP(x,y);
            if((i%2 == 1 && j%2 == 1) ) upp[cu++] = MP(x,y);
        }
    }

    sort(lowp,lowp+cl);
    n = 0;
  //  for(int i=0; i<cl; i++)    cout<<i<<" "<<lowp[i].first<<" "<<lowp[i].second<<endl;

    for(int i = 0,j; i < cl; i = j) {
        //找边界点(红点)
        for(j = i; j < cl && lowp[j].first == lowp[i].first; ++j);           //从i开始,到cl为止的点,如果x坐标相等,j++,越过横坐标相同的点(已排序)
        while(n > 0 && lowp[n-1].second >= lowp[i].second) --n;  //如果纵坐标减小,则更新边界点
        lowp[n++] = lowp[i];
    }
    cl = n;

    //for(int i=0;i<cl;i++)    cout<<"d"<<i<<" "<<lowp[i].first<<" "<<lowp[i].second<<endl;

    sort(upp,upp+cu);
    n = 0;
    for(int i = 0,j; i < cu; i = j) {
        for(j = i; j < cu && upp[j].first == upp[i].first; ++j);
        if(!n || upp[j-1].second > upp[n-1].second) upp[n++] = upp[j-1];
    }
    cu = n;
    //for(int i=0;i<cu;i++)    cout<<"u"<<i<<" "<<upp[i].first<<" "<<upp[i].second<<endl;

    int a,b,low,up;
    for(int i = 0; i < m; ++i) {
        scanf("%d%d",&a,&b);
        low = lower_bound(lowp,lowp+cl,MP(a,-ms63))-lowp;
        up = lower_bound(upp,upp+cu,MP(a,ms63))-upp;
        if(low < cl&&up<=cu&& b >= lowp[low].second && b <= upp[up-1].second) ans[i] = '1';
        else ans[i] = '0';
    }
    ans[m] = 0;
    puts(ans);
}


int main() {
  // freopen("in.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值