cf1200 D. White Lines(前缀和)

题意:

给定一个01方阵。把某个 k*k 子矩阵变成0,使得全0行的数量与全0列的数量之和最大。输出和。

思路:

枚举 \((i,j)\) 作为子矩阵的左上角,预处理出能新增的全0行数+能新增的列数,最后加上原方阵中的行数列数。

甚至不用二位前缀和,只用每行/每列的前缀和

#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int n, k, a[N][N], newr[N][N], newc[N][N];
int sr[N][N], sc[N][N], ans;
signed main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
        {
            char c; scanf(" %c", &c);
            if(c == 'B') a[i][j] = 1;
        }

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            sr[i][j] = sr[i][j-1] + a[i][j], //每行的前j前缀和
            sc[j][i] = sc[j][i-1] + a[i][j]; //每列的前i前缀和

    for(int i = 1; i <= n; i++) //前i行覆盖l~r列新增的行
        for(int l = 1, r = l + k - 1; r <= n; l++, r++)
            newr[i][l] = newr[i-1][l] + (sr[i][n] && sr[i][n] == sr[i][r]-sr[i][l-1]);
    for(int j = 1; j <= n; j++) //前j列覆盖l~r行新增的列
        for(int l = 1, r = l + k - 1; r <= n; l++, r++)
            newc[j][l] = newc[j-1][l] + (sc[j][n] && sc[j][n] == sc[j][r]-sc[j][l-1]);

    for(int i = 1; i + k - 1 <= n; i++)
        for(int j = 1; j + k - 1 <= n; j++)
        {
            int newrows = newr[i+k-1][j] - newr[i-1][j];
            int newcols = newc[j+k-1][i] - newc[j-1][i];
            ans = max(ans, newrows + newcols);
        }
    //原本就有的行列数
    for(int i = 1; i <= n; i++) ans += (sr[i][n] == 0), ans += (sc[i][n] == 0);

    printf("%d", ans);

    return 0;
}

posted @ 2021-12-24 13:07  Bellala  阅读(47)  评论(0)    收藏  举报