5017. 拍苍蝇

题目大意

给定一个平面坐标系,其中有 n 个整点。给定一个多边形,求在给定范围内,有多少个位置可以放这个多边形,满足多边形内没有给定的整点。

Data Constraint
1Xp,Yp500,nXpYp

题解

先用射线法做出一个bitset矩阵,记录那些点在多边形内。
然后原图建一个bitset,枚举多边形左下角的位置,暴力bitset and一下。

时间复杂度: O(Xp432)

SRC

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<cmath>
using namespace std ;

#define N 250000 + 10
#define M 500 + 10
struct DOT {
    int x , y ;
    DOT ( int X = 0 , int Y = 0 ) { x = X , y = Y ; }
} fly[N] , P[N] ;

bitset < M > Map[M] , POL[M] , tmp ;

bool flag[M][M] ;
int S[M][M] ;
int Xp , Yp , n , Num , ans ;
int Minx , Miny , Maxx , Maxy ;

int main() {
    freopen( "fly.in" , "r" , stdin ) ;
    freopen( "fly.out" , "w" , stdout ) ;
    scanf( "%d%d%d" , &Xp , &Yp , &n ) ;
    for (int i = 1 ; i <= n ; i ++ ) {
        scanf( "%d%d" , &fly[i].x , &fly[i].y ) ;
        Map[fly[i].x][fly[i].y] = 1 ;
    }
    Minx = Miny = 0x7FFFFFFF ;
    Maxx = Maxy = -0x7FFFFFFF ;
    scanf( "%d" , &Num ) ;
    for (int i = 1 ; i <= Num ; i ++ ) {
        scanf( "%d%d" , &P[i].x , &P[i].y ) ;
        Minx = min( Minx , P[i].x ) ;
        Miny = min( Miny , P[i].y ) ;
    }
    for (int i = 1 ; i <= Num ; i ++ ) {
        P[i].x -= Minx ;
        P[i].y -= Miny ;
        Maxx = max( Maxx , P[i].x ) ;
        Maxy = max( Maxy , P[i].y ) ;
    }
    for (int k = 1 ; k <= Num ; k ++ ) {
        int i = k , j = k % Num + 1 ;
        if ( P[i].x > P[j].x ) swap( i , j ) ;
        if ( P[i].x == P[j].x ) {
            for (int l = min( P[i].y , P[j].y ) ; l <= max( P[j].y , P[i].y ) ; l ++ ) flag[P[i].x][l] = -1 ;
            continue ;
        }
        double del = (double)(P[j].y - P[i].y) / (P[j].x - P[i].x) ;
        double y = P[i].y ;
        for (int l = P[i].x ; l <= P[j].x ; l ++ , y += del ) {
            int now = y ;
            if ( fabs(y-(double)now) <= 1e-6 ) flag[l][now] = 1 ;
            if ( l < P[j].x ) S[l][now+1] ++ ;
        }
    }
    for (int x = 0 ; x <= Maxx ; x ++ ) {
        for (int y = 1 ; y <= Maxy ; y ++ ) S[x][y] += S[x][y-1] ;
    }
    for (int x = 0 ; x <= Maxx ; x ++ ) {
        for (int y = 0 ; y <= Maxy ; y ++ ) {
            if ( flag[x][y] || (S[x][y] & 1) ) {
                POL[x][y] = 1 ;
            }
        }
    }
    for (int x = 0 ; x <= Xp - Maxx ; x ++ ) {
        for (int y = 0 ; y <= Yp - Maxy ; y ++ ) {
            bool ok = 1 ;
            for (int i = 0 ; i <= Maxx ; i ++ ) {
                tmp = POL[i] & (Map[x+i] >> y) ;
                if ( tmp.any() ) { ok = 0 ; break ; }
            }
            ans += ok ;
        }
    }
    printf( "%d\n" , ans ) ;
    return 0 ;
}

以上.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值