『题解』Luogu P8033 [COCI2015-2016#7] Prozor
题目大意
一扇 \(R \times S\) 的窗户上有一些苍蝇。有一把苍蝇拍,它可以消灭 \(K \times K\) 的矩阵内(不含边界)的苍蝇。
选择一种苍蝇拍放置的位置,使得被消灭的苍蝇数量最多。输出被消灭的苍蝇的最大值和窗户的样子。如果有多种方案,输出任意一种即可。
思路
二维前缀和(不懂可以参考我这篇博客 )。
考虑枚举苍蝇拍左上角位置,每次对枚举到的矩阵进行前缀和查询操作,更新最大值和坐标,最后画上去即可。时间复杂度 \(\mathcal{O}(nm)\)。
就这么简单,代码里的注释应该够详细了吧?
代码
#include <iostream>
using namespace std;
const int N=105; // 数据范围
int r,s,k; // 题目给出的数据
int sum[N][N],ans,x,y; // 前缀和数组sum,答案 ans 和坐标 x,y
char a[N][N]; // 就先用一下 char 吧(
int main(){
cin >> r >> s >> k;
for(int i=1; i<=r; i++){
for(int j=1; j<=s; j++){
cin >> a[i][j];
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(a[i][j]=='*');
// 二维前缀和
}
}
// 枚举苍蝇拍左上角
// 要确保边界不出错
// 先用 l1,l2 记录一下,以免重复计算(感觉没啥用/kk)
int l1=l1=r-k+1,l2=s-k+1,t; // t 用于临时存储
k-=2; // 不算边界,所以 k-=2(其实就是懒得打 '-2'
for(int i=1; i<=l1; i++){
for(int j=1; j<=l2; j++){
t=sum[i+k][j+k]-sum[i][j+k]-sum[i+k][j]+sum[i][j];
// i,j 枚举的是左上角的 '+' 号
// sum[i][j] 包括边界,直接减就刚好算到内部
if(t>ans){
ans=t; // 更新答案
x=i,y=j;
}
}
}
k++; // 只加一个是因为后面每次写都要减一,省力气(
l1=x+k,l2=y+k; // 还是记录
// 开始作画了!
for(int i=x; i<=l1; i++) a[i][y]=a[i][y+k]='|'; // 左边和右边的边框
for(int i=y; i<=l2; i++) a[x][i]=a[x+k][i]='-'; // 上面和下面
a[x][y]=a[x+k][y]=a[x][y+k]=a[x+k][y+k]='+'; // 四个角
// 愉快地输出吧!
cout << ans << endl;
for(int i=1; i<=r; i++){
for(int j=1; j<=s; j++){
putchar(a[i][j]);
}
puts("");
}
return 0;
}