链接:
@[toc]
时间限制: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; }