题目链接:https://vjudge.net/problem/CodeForces-1200D
转自:https://www.cnblogs.com/wawcac-blog/p/11355416.html
题意:有一个n * n的矩阵,W代表白色,B代表黑色,现在有一个k * k大小的橡皮擦,问只用一次,可以创造最多多少W组成的直线,只有水平和竖直且长度为n。
思路:类似于滑动窗口,分别向右和向下滑动。不过多了很多预处理。
#include<bits/stdc++.h>
using namespace std;
int n,k;
const int maxn=2005;
int u[maxn],d[maxn],l[maxn],r[maxn];
int row[maxn][maxn],col[maxn][maxn],wr,wc;
char s[2005];
int main()
{
scanf("%d%d",&n,&k);
getchar();
for(int i=1; i<=n; i++)
{
scanf("%s",s+1);
for(int j=1; j<=n; j++)
{
if(s[j]=='B')
{
r[i]=j;//每行中最后出现B的位置
if(!l[i])//每行中最先出现B的位置
l[i]=j;
d[j]=i;//每列中最后出现B的位置
if(!u[j])//每列中最先出现B的位置
u[j]=i;
}
}
}
for(int i=1; i<=n; i++)//图中已经存在了多少白线
{
if(!u[i])
wc++;
if(!l[i])
wr++;
}
for(int i=1; i+k<=n+1; i++)//按照行搜索
{
for(int j=1; j<=k; j++)//统计原先方框内就有的
{
if(d[j]&&d[j]<=i+k-1&&u[j]>=i)
col[i][1]++;
}
for(int j=2; j+k<=n+1; j++)//向右滑动
{
col[i][j]=col[i][j-1];
if(d[j-1]&&d[j-1]<=i+k-1&&u[j-1]>=i)//如果有一条白线刚刚滑出
col[i][j]--;
if(d[j+k-1]&&d[j+k-1]<=i+k-1&&u[j+k-1]>=i)
col[i][j]++;
}
}
for(int i=1;i+k<=n+1;i++)
{
for(int j=1;j<=k;j++)
{
if(r[j]&&r[j]<=i+k-1&&l[j]>=i)
row[1][i]++;
}
for(int j=2;j+k-1<=n;j++)
{
row[j][i]=row[j-1][i];
if(r[j-1]&&r[j-1]<=i+k-1&&l[j-1]>=i)
row[j][i]--;
if(r[j+k-1]&&r[j+k-1]<=i+k-1&&l[j+k-1]>=i)
row[j][i]++;
}
}
int ans=-1;
for(int i=1;i+k<=n+1;i++)
{
for(int j=1;j+k<=n+1;j++)
{
ans=max(ans,col[i][j]+row[i][j]);
}
}
printf("%d\n",ans+wc+wr);
}