[Nowcoder 2018ACM多校第二场J] farm

题目大意: 给出一个n*m的矩阵农场, G[i][j]代表着对应植物所需的肥料类型, 有T组操作, 对第i个操作是对子矩阵G[x1[i]…x2[i]][y1[i]…y2[i]]施以肥料k[i], 若植物得到了错误的肥料会死亡。 求T组操作后死亡的植物总数。 (nm106,G[i][j],k[i]106) ( n ∗ m ≤ 10 6 , G [ i ] [ j ] , k [ i ] ≤ 10 6 )

题目思路: 先考虑一种简单的情况, 如果只有0和1这两种, 那么可以直接用二维的差分来维护各个施肥。 即对于第i个操作, f[x1[i]][y1[i]]++, f[x2[i]+1][y1[i]]–, f[x1[i]][y2[i]]–, f[x2[i]+1][y2[i]+1]++, 最后求一遍矩阵前缀和求可以求出各个植物被施肥的次数, 分别对肥料1和肥料0都这么做, 则一个植物会产生贡献就是与其相反的肥料施肥次数大于0。 最后考虑整个题目, 可以枚举各个二进制位, 考虑两个数不同则至少有一个二进制位上是不同的, 同样按照01情况维护即可。

Code:

#include <map>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define ll long long
#define id(i, j) (m * ((i) - 1) + (j))

const int N = (int)1e6 + 10;

int n, m, T;
int G[N], x1[N], x2[N], Y1[N], y2[N], v[N], ans[N];
int f[N][2];

int main(){
    scanf("%d %d %d", &n, &m, &T);
    for (int i = 1; i <= n * m; i ++)
        scanf("%d", G + i);

    for (int i = 1; i <= T; i ++)
        scanf("%d %d %d %d %d", x1 + i, Y1 + i, x2 + i, y2 + i, v + i);

    for (int h = 0; h < 20; h ++){
        memset(f, 0, sizeof(f));

        for (int i = 1; i <= T; i ++){
            f[id(x1[i], Y1[i])][(v[i] >> h) & 1] ++;
            if (x2[i] < n) f[id(x2[i] + 1, Y1[i])][(v[i] >> h) & 1] --;
            if (y2[i] < m) f[id(x1[i], y2[i] + 1)][(v[i] >> h) & 1] --;
            if (x2[i] < n && y2[i] < m) f[id(x2[i] + 1, y2[i] + 1)][(v[i] >> h) & 1] ++;    
        }


        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= m; j ++){
                for (int k = 0; k <= 1; k ++){
                    if (j > 1) f[id(i, j)][k] += f[id(i, j - 1)][k];
                    if (i > 1) f[id(i, j)][k] += f[id(i - 1, j)][k];
                    if (i > 1 && j > 1) f[id(i, j)][k] -= f[id(i - 1, j - 1)][k];
                }

                if ((G[id(i, j)] >> h) & 1) ans[id(i, j)] |= (f[id(i, j)][0] > 0);
                else ans[id(i, j)] |= (f[id(i, j)][1] > 0);
            }

    }

    for (int i = 1; i <= n * m; i ++)
        ans[i] += ans[i - 1];

    printf("%d", ans[n * m]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值