思路
前缀和 + 差分 + 贡献
a[i][j] <==> 二维差分, s[i][j] <==> 二维前缀和. i 为 ——>x, j 为 ——>y.
分别求各行各列的贡献
即: 枚举第i行,判断有无’B’.
如果没有,a[1][1] ++ <==> 对所有贡献 + 1;
如果有,记录’B’的位置最左端l和最右端r,判断是否可以被k * k覆盖.不能肯定无贡献;能的话该k * k的最大范围的矩形左上角坐标(i - k + 1, r - k + 1)(可能会越界)和右下角坐标(i, l),该范围对该行贡献 + 1;
最后求前缀和s[i][j], 找到最大值输出.
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010;
int n, k;
char g[N][N];
int s[N][N];
int main()
{
cin >> n >> k;
for(int i = 1; i <= n; i ++ ) cin >> g[i] + 1;
for(int i = 1; i <= n; i ++ )
{
int l = 0, r = 0;
for(int j = 1; j <= n; j ++ )
{
if(g[i][j] == 'B')
{
if(l == 0) l = j, r = j;
else r = j;
}
}
if(l == 0 && r == 0)
{
s[1][1] ++ ;
continue;
}
if(r - l + 1 > k) continue;
int x1 = max(1, i - k + 1), y1 = max(1, r - k + 1), x2 = i, y2 = l;
s[x1][y1] ++ , s[x2 + 1][y1] -- , s[x1][y2 + 1] -- , s[x2 + 1][y2 + 1] ++ ;
}
for(int j = 1; j <= n; j ++ )
{
int u = 0, d = 0;
for(int i = 1; i <= n; i ++ )
{
if(g[i][j] == 'B')
{
if(u == 0) u = i, d = i;
else d = i;
}
}
if(u == 0 && d == 0)
{
s[1][1] ++ ;
continue;
}
if(d - u + 1 > k) continue;
int x1 = max(1, d - k + 1), y1 = max(1, j - k + 1), x2 = u, y2 = j;
s[x1][y1] ++ , s[x2 + 1][y1] -- ,s[x1][y2 + 1] -- , s[x2 + 1][y2 + 1] ++ ;
}
int res = 0;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ )
{
s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
res = max(res, s[i][j]);
}
cout << res << endl;
return 0;
}