链接:

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

帕秋莉掌握了一种土属性魔法

这种魔法可以在一片k×k大小的一个正方形区域内产生地震

但是如果某片即将产生地震的区域内有建筑物,帕秋莉会停止施法

整个地图大小为n×m,其中一些地方有建筑

请问有多少种可能的情况,使得帕秋莉会停止施法

输入描述:

第一行三个数n, m, k,意义见描述 接下来一个n×m的01矩阵表示这篇区域的情况,1表示这个地方有建筑

输出描述:

输出一个数表示答案

示例1
输入

4 4 2
1000
0100
0000
0001

输出

5

备注:

对于30%的数据,n, m≤30 对于100%的数据,n, m≤1000,k≤min(n, m)

题解:

关于二维前缀和的题目
我们都知道一维前缀和,二维前缀和就是在一维的基础上建立的,可以通过二维前缀和求出矩阵内一个任意的子矩阵的数的和。
dp [ i ] [ j ] 表示表示一个矩阵内数的总和
(1,1)与(i,j)这两个点分别为这个矩阵的左上角,和右下角。
状态转移方程为
dp [ i ] [ j ] = d p [ i - 1 ] [ j ] + dp [ i ] [j - 1 ] - d p [ i - 1 ] [ j -1 ] + a [ i ] [ j ]

大致可以理解成:整个矩形区域=左边区域(1,1)~ (i,j-1)+上面区域(1,1)~(i-1,j),减去重复区域(红色部分),再加上蓝色部分( 当前点( i , j ))
图片选自

放在本题
当矩阵某点 ( i , j ) 的值为1时,dp [ i ] [ j ] ++
然后求出二维前缀和的值,
然后我们可以通过这些值求出 矩阵的大小是固定的 k * k 的情况是否符合要求

我们枚举正方形右下角的点 ( i , j )
对于(1,1)到(i,j)的矩阵,
sum=dp [ i+k−1 ] [ j+k−1 ]− dp [ i+k−1 ][ j−1 ]−dp [ i−1 ][ j+k−1 ]+dp [ i − 1 ] [ j− 1 ]
可以理解成二维前缀和的那个式子倒过来,
用(i,j)的二维前缀和,也就是图中整个矩形,减去上部分,再减去左部分,加上被多减的红色部分,剩下的就是蓝色部分,也就是我们所求的k*k大的矩阵
sum>0,说明符合条件,结果加一

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e3+4;
char a[maxn][maxn];
int dp[maxn][maxn];
int n,m,k;
int main()
{
   
     int sum=0;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
		{
   
            cin>>a[i][j];
        }
   
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
   
        	dp[i][j]+=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1];
        	if(a[i][j]=='1')dp[i][j]++;
		}
            
    for(int i=k;i<=n;i++)
        for(int j=k;j<=m;j++)
		{
   
            if(dp[i][j]-dp[i-k][j]-dp[i][j-k]+dp[i-k][j-k])sum++;
        }
    cout<<sum<<endl;
    return 0;
}