题目大意:

题目链接:​​https://codeforces.com/problemset/problem/1200/D​

给出一个n×nn\times nn×n的黑白网格图,问用一个m×mm\times mm×m的白色网格覆盖原图的一部分后最多有多少行列全部为白色。


思路:

考虑对于每一条边,如果我们要把它染成白色,那么对应白色矩形的左上角坐标的区间范围是多少。

假设这条边的最左端黑色位置的下标为lll,最右端下标为rrr,那么这个矩形右边界一定要≥r\geq r≥r,左边界一定要≤l\leq l≤l。所以我们算出这个矩形左上角横坐标的区间,用前缀和搞一下即可。

同理,对于纵向的边我们也可以求出横向的区间范围。这样一共有2n2n2n条边,每条边的最大范围为mmm,时间复杂度O(nm)O(nm)O(nm)。

然后跑一下前缀和就好了。注意答案要加上一开始就全部为白色的数量。


代码:

#include <cstdio>
#include <algorithm>
using namespace std;

const int N=2010;
int n,m,s1[N][N],s2[N][N],ans,cnt;
char ch[N][N];

struct node
{
int l,r;
}a[N],b[N];

int main()
{
scanf("%d%d",&n,&m);
if (m>=n)
{
printf("%d",n*2);
return 0;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
while (ch[i][j]=getchar()) if (ch[i][j]=='W'||ch[i][j]=='B') break;
if (ch[i][j]=='B')
{
if (!a[i].l) a[i].l=j;
a[i].r=j;
if (!b[j].l) b[j].l=i;
b[j].r=i;
}
}
for (int i=1;i<=n;i++)
{
bool flag=1;
for (int j=1;j<=n;j++)
if (ch[i][j]=='B')
{
flag=0;
break;
}
if (flag) cnt++;
}
for (int i=1;i<=n;i++)
{
bool flag=1;
for (int j=1;j<=n;j++)
if (ch[j][i]=='B')
{
flag=0;
break;
}
if (flag) cnt++;
}
for (int i=1;i<=n;i++)
if (a[i].r-a[i].l+1<=m)
{
int l=a[i].l,r=a[i].r;
for (int j=max(1,i-m+1);j<=i;j++)
s1[j][max(r-m+1,1)]++,s1[j][l+1]--;
}
for (int i=1;i<=n;i++)
if (b[i].r-b[i].l+1<=m)
{
int l=b[i].l,r=b[i].r;
for (int j=max(1,i-m+1);j<=i;j++)
s2[max(r-m+1,1)][j]++,s2[l+1][j]--;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
s1[i][j]+=s1[i][j-1];
s2[i][j]+=s2[i-1][j];
if (s1[i][j]+s2[i][j]>ans)
ans=s1[i][j]+s2[i][j];
}
printf("%d",ans+cnt);
return 0;
}