『题解』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;
}
posted @ 2022-01-21 21:24  仙山有茗  阅读(34)  评论(0编辑  收藏  举报