引言:
矩陣前綴和
矩陣前綴和,即一個矩陣的一片區域的和,如圖:
基本公式就是:pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+a[i][j];
題目:
祕法地震
鏈接:https://ac.nowcoder.com/acm/contest/2272/C
來源:牛客網
題目描述
帕秋莉掌握了一種土屬性魔法
這種魔法可以在一片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)
思路:
求出矩陣的前綴和,然後對於每個i<=n-k+1,j<=m-k+1區間內的點(i,j),判斷它的右下方的k*k區域的前綴和是否大於1,若是的話,說明包含了建築物。(跟暴力的思路是一樣的,只是少了兩層循環~~~~)
對於每個點的k*k區域求法是這樣的:
int judge(int x,int y){
int ex=x+k-1;
int ey=y+k-1;
return pre[ex][ey]-pre[x-1][ey]-pre[ex][y-1]+pre[x-1][y-1];
}
其實不難理解,就是將上面通式中的a[i][j]換成了一個大的k*k矩陣。
完整代碼:
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void read(T &res)
{
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
const int maxn=3005;
char b[maxn][maxn];
int a[maxn][maxn],pre[maxn][maxn];
int n,m,k,sum=0;
int judge(int x,int y){
int ex=x+k-1;
int ey=y+k-1;
return pre[ex][ey]-pre[x-1][ey]-pre[ex][y-1]+pre[x-1][y-1];
}
int main(){
read(n);
read(m);
read(k);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%c",&b[i][j]);
}
getchar();
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=b[i][j]-'0';
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+a[i][j];
}
}
for(int i=1;i<=n-k+1;i++){
for(int j=1;j<=m-k+1;j++){
if(judge(i,j)){
sum++;
}
}
}
printf("%d\n",sum);
return 0;
}