Codeforces 1080C 题解(思维+二维前缀和)

题面

传送门

题目大意:

有一个黑白的棋盘,现在将棋盘上的一个子矩形全部染成黑色,另一个子矩形全部染成白色

求染完色后黑,白格子的总数

分析

我们可以发现,对于一个(1,1)到(x,y)的矩形,若xy为偶数,则黑、白的个数都是 $ \frac{xy}{2} $

若xy为奇数,则黑格个数为\(\ [ \frac{xy}{2} \ ]\),白格个数为\(\ [ \frac{xy}{2} \ ]+1\)

因此用二维前缀和的方法就可以求出任意子矩形内的黑,白格子个数

long long get_white(long long x,long long y) {
    if((x*y)%2==0) return (x*y)/2;
    else {
        return (x*y)/2+1;
    }
}
long long get_black(long long x,long long y) {
    if((x*y)%2==0) return (x*y)/2;
    else {
        return (x*y)/2;
    }
}
long long get_rec_black(long long x1,long long y1,long long x2,long long y2) {
    return get_black(x2,y2)-get_black(x1-1,y2)-get_black(x2,y1-1)+get_black(x1-1,y1-1);
}
long long get_rec_white(long long x1,long long y1,long long x2,long long y2) {
    return get_white(x2,y2)-get_white(x1-1,y2)-get_white(x2,y1-1)+get_white(x1-1,y1-1);
}

然后考虑修改:

对于染黑的操作,设wsum,bsum分别表示整个棋盘里的白,黑格子个数,初始wsum,bsum都是原本棋盘里黑,白格子的个数

s表示染黑的矩形内部原来白色格子个数,则wsum=wsum-s,bsum=bsum+s

染白操作同理

wsum=get_white(n,m);
bsum=get_black(n,m);
s1=get_rec_black(x1,y1,x2,y2);
wsum+=s1;
bsum-=s1;

但这样会导致一个问题,若染黑和染白的矩形有公共部分,那么会出现错误

因此我们染黑时先不考虑公共部分(染白时直接染),把公共部分从答案里面减去

再分析公共部分对答案的影响

设公共部分面积为same

则bsum+=same,wsum-=same

这样我们就在\(O(1)\)时间内求出了答案

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int t;
long long n,m;
long long x1,y1,x2,y2;
long long x3,y3,x4,y4;
long long wsum,bsum;
long long get_white(long long x,long long y) {
    if((x*y)%2==0) return (x*y)/2;
    else {
        return (x*y)/2+1;
    }
}
long long get_black(long long x,long long y) {
    if((x*y)%2==0) return (x*y)/2;
    else {
        return (x*y)/2;
    }
}

long long get_rec_black(long long x1,long long y1,long long x2,long long y2) {
    return get_black(x2,y2)-get_black(x1-1,y2)-get_black(x2,y1-1)+get_black(x1-1,y1-1);
}

long long get_rec_white(long long x1,long long y1,long long x2,long long y2) {
    return get_white(x2,y2)-get_white(x1-1,y2)-get_white(x2,y1-1)+get_white(x1-1,y1-1);
}

long long minx,miny,maxx,maxy;
int get_inter(long long x1,long long y1,long long x2,long long y2,long long x3,long long y3,long long x4,long long y4) {
    minx=max(x1,x3);
    miny=max(y1,y3);
    maxx=min(x2,x4);
    maxy=min(y2,y4); 
    if(minx>maxx||miny>maxy) return -1;
    else return 1;
} 

int main() {
    long long s1,s2,same;
    scanf("%d",&t);
    while(t--) {
        scanf("%I64d %I64d",&n,&m);
//      swap(n,m);
        scanf("%I64d %I64d %I64d %I64d",&x1,&y1,&x2,&y2);
        scanf("%I64d %I64d %I64d %I64d",&x3,&y3,&x4,&y4);
        wsum=get_white(n,m);
        bsum=get_black(n,m);
        s1=get_rec_black(x1,y1,x2,y2);
        wsum+=s1;
        bsum-=s1;
        if(get_inter(x1,y1,x2,y2,x3,y3,x4,y4)==-1) {
            s2=get_rec_white(x3,y3,x4,y4);
            bsum+=s2;
            wsum-=s2;
        } else {
            s2=get_rec_white(x3,y3,x4,y4)-get_rec_white(minx,miny,maxx,maxy);
            bsum+=s2;
            wsum-=s2;
            bsum+=(maxy-miny+1)*(maxx-minx+1);
            wsum-=(maxy-miny+1)*(maxx-minx+1);
        }

        printf("%I64d %I64d\n",wsum,bsum);
    }
}

转载于:https://www.cnblogs.com/birchtree/p/10013492.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值