题目描述:
帕秋莉掌握了一种土属性魔法
这种魔法可以在一片k×k大小的一个正方形区域内产生地震
但是如果某片即将产生地震的区域内有建筑物,帕秋莉会停止施法
整个地图大小为n×m,其中一些地方有建筑
请问有多少种可能的情况,使得帕秋莉会停止施法
输入描述:
第一行三个数n, m, k,意义见描述
接下来一个n×m的01矩阵表示这篇区域的情况,1表示这个地方有建筑
输出描述:
输出一个数表示答案
输入
4 4 2 1000 0100 0000 0001
输出
5
题目不难理解,写的时候不会ToT
暴力所有的k * k的区间即可,重点是怎么求区间内有多少个建筑
因为这是一个二维的图,因此可以用二维前缀和来存储从端点 (1 , 1) 开始到(x, y)这个点的矩形有多少个建筑,转移方程很简单
dp[x][y] = dp[x - 1][y] + dp[x][y - 1] - dp[x - 1][y - 1];//一般形式
//本题目中应该是
dp[x][y] = dp[x - 1][y] + dp[x][y - 1] - dp[x - 1][y - 1] + mp[x][y];
很简单,画个图就可以直接得出
证明其实就是一个简单的容斥原理
dp[ i ][ j ]包含了 dp[ i - 1][ j ] 和 dp[ i ][j - 1],因此可以写成两部分相加的形式,而两部分相加后会多出dp[ i - 1][j - 1]这一部分,减去即可
求某一区间的和也很简单,本题中是这样的
bool check(int bx, int by){
int ex = bx + k - 1;
int ey = by + k - 1;
return pre[ex][ey] - pre[bx - 1][ey] - pre[ex][by - 1] + pre[bx - 1][by - 1];
}
求出区间的左上和右下端点,然后计算和,计算方法也是容斥原理,图来
求 (x1, y1) 到 (x2, y2) 的和,先求出 (1, 1) 到 (x2, y2) 的和即 dp[ x2 ][ y2 ],分别减去两边多出的部分dp[ x2 - 1][y1] 和 dp[x1][y2 - 1],再加上多删除的部分即可
本题直接把二维前缀和应用到题目中即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1100;
char mp[1100][1100];
int pre[N][N];
int n, m, k;
bool check(int bx, int by){
int ex = bx + k - 1;
int ey = by + k - 1;
return pre[ex][ey] - pre[bx - 1][ey] - pre[ex][by - 1] + pre[bx - 1][by - 1];
}
int main()
{
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= n; i++){
scanf("%s", mp[i] + 1);
}
memset(pre, 0, sizeof pre);
for (int i = 1; i <= n; i++){//pre_work
for (int j = 1; j <= m; j++){
pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + mp[i][j] - '0';
// printf("%d ", pre[i][j]);
}
// puts("");
}
int res = 0;
for (int i = 1; i <= n - k + 1; i++){
for (int j = 1; j <= m - k + 1; j++){
if(check(i, j)){
++res;
}
}
}
printf("%d\n", res);
return 0;
}