D. White Lines
Problem
Gildong has bought a famous painting software cfpaint. The working screen of cfpaint is square-shaped consisting of \(n\) rows and \(n\) columns of square cells. The rows are numbered from \(1\) to \(n\), from top to bottom, and the columns are numbered from \(1\) to \(n\), from left to right. The position of a cell at row \(r\) and column \(c\) is represented as \((r,c)\). There are only two colors for the cells in cfpaint — black and white.
There is a tool named eraser in cfpaint. The eraser has an integer size \(k (1 \leq k \leq n)\). To use the eraser, Gildong needs to click on a cell \((i,j)\) where \(1 \leq i,j \leq n−k+1\). When a cell \((i,j)\) is clicked, all of the cells \((i′,j′)\) where \(i \leq i′ \leq i+k−1\) and \(j \leq j′ \leq j+k−1\) become white. In other words, a square with side equal to \(k\) cells and top left corner at \((i,j)\) is colored white.
A white line is a row or a column without any black cells.
Gildong has worked with cfpaint for some time, so some of the cells (possibly zero or all) are currently black. He wants to know the maximum number of white lines after using the eraser exactly once. Help Gildong find the answer to his question.
Input
The first line contains two integers \(n\) and \(k (1 \leq k \leq n \leq 2000)\) — the number of rows and columns, and the size of the eraser.
The next \(n\) lines contain \(n\) characters each without spaces. The \(j^{th}\) character in the \(i^{th}\) line represents the cell at \((i,j)\). Each character is given as either 'B' representing a black cell, or 'W' representing a white cell.
Output
Print one integer: the maximum number of white lines after using the eraser exactly once.
Examples
input
4 2
BWWW
WBBW
WBBW
WWWB
output
4
input
3 1
BWB
WWB
BWB
output
2
input
5 3
BWBBB
BWBBB
BBBBB
BBBBB
WBBBW
output
2
input
2 2
BW
WB
output
4
input
2 1
WW
WW
output
4
Note
In the first example, Gildong can click the cell \((2,2)\), then the working screen becomes:
BWWW
WWWW
WWWW
WWWB
Then there are four white lines — the \(2^{nd}\) and \(3^{rd}\) row, and the \(2^{nd}\) and \(3^{rd}\) column.
In the second example, clicking the cell \((2,3)\) makes the \(2^{nd}\) row a white line.
In the third example, both the \(2^{nd}\) column and \(5^{th}\) row become white lines by clicking the cell \((3,2)\).
想法 (官方题解)
Let's consider a single row that contains at least one black cell. If the first appearance of a black cell is at the \(l^{th}\) column and the last appearance of a black cell is at the \(r^{th}\) column, we can determine whether it becomes a white line when a certain cell \((i,j)\) is clicked in \(O(1)\), after some preprocessing. It becomes a white line if and only if a cell \((i,j)\) is clicked where the row is at \([i,i+k−1]\) and \(j \leq l \leq r \leq j+k−1\). We just need to compute \(l\) and \(r\) in advance.
Now let's consider all \(n\) rows (not columns). First, count all rows that are already white lines before clicking. Then we count the number of white rows when the cell \((1,1)\) is clicked, by applying the above method to all rows from \(1\) to \(k\). Ignore the already-white rows that we counted before. So far we obtained the number of white rows when the cell \((1,1)\) is clicked. From now, we slide the window. Add the \(k+1^{th}\) row and remove the \(1^{st}\) row by applying the same method to them, and we obtain the number of white rows when the cell \((2,1)\) is clicked. We can repeat this until we calculate all \(n−k+1\) cases for clicking the cells at the \(1^{st}\) column. Then we repeat the whole process for all \(n−k+1\) columns.
The same process can be done for counting white columns, too. Now we know the number of white rows and white columns when each cell is clicked, so we can find the maximum value among their sums.
Time complexity: \(O(n^2)\)
配上图,一开始我也是这么想的,但是想出来是个\(O(n^2k)\)的假算法,T在第12个点,后来看了题解发现其实可以预处理一下,计算橡皮擦擦\((i,j)\)到\((i+k-1,j+k-1)\)这个大正方形对行列的贡献的时候可以优化到\(O(n^2)\),不需要每次都重复计算K行K列。
The Code Of My Program
/*********************
*@Author: ChenShou *
*@Language: C++11 *
*********************/
//#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:102400000,102400000")
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<iomanip>
#include<numeric>
#include<cctype>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
#define endl "\n"
using namespace std;
typedef long long ll;
//typedef __int128 lll;
//const int N=100000+10;
const int M=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-9;
const int INF = 0x3f3f3f3f;
inline ll read(){
long long x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
ll n,k;
int mp[2005][2005]={0};
char paint[2005];
int add_r[2005][2005]={0},add_c[2005][2005]={0};
int main()
{
#ifdef DEBUG
freopen("input.in", "r", stdin);
//freopen("output.out", "w", stdout);
#endif
//cout.tie(0);
//ll t ;
//scanf("%lld",&t);
//while(t--){
//}
n=read(),k=read();
for(int i= 1 ;i<=n ; i++){
scanf("%s",paint+1);
int mmin=-1,mmax=-1;
for(int j=1;j<=n;j++){
mp[i][j]=(paint[j]=='W'?0:1);// W 0 // B 1
if(mp[i][j]){
if(mmin==-1)mmin=j;
mmax=j;
}
}
mp[i][n+1]=mmin,mp[i][n+2]=mmax;
}
for(int j= 1 ;j<=n ; j++){
int mmin=-1,mmax=-1;
for(int i=1;i<=n;i++){
if(mp[i][j]){
if(mmin==-1)mmin=i;
mmax=i;
}
}
mp[n+1][j]=mmin,mp[n+2][j]=mmax;
}
for(int i=1;i+k-1<=n;i++){
for(int j=1;j+k-1<=n;j++){
if(j==1)
for(int cc=j;cc<=j+k-1;cc++){
if(mp[n+1][cc]!=-1&&i<=mp[n+1][cc]&&i+k-1>=mp[n+2][cc])
add_c[i][j]++;
}
else {
int tem=0;
if(mp[n+1][j-1]!=-1&&i<=mp[n+1][j-1]&&i+k-1>=mp[n+2][j-1])tem--;
if(mp[n+1][j+k-1]!=-1&&i<=mp[n+1][j+k-1]&&i+k-1>=mp[n+2][j+k-1])tem++;
add_c[i][j]=add_c[i][j-1]+tem;
}
}
}
for(int j=1;j+k-1<=n;j++){
for(int i=1;i+k-1<=n;i++){
if(i==1)
for(int rr=i;rr<=i+k-1;rr++){
if(mp[rr][n+1]!=-1&&j<=mp[rr][n+1]&&j+k-1>=mp[rr][n+2])
add_r[i][j]++;
}
else {
int tem=0;
if(mp[i-1][n+1]!=-1&&j<=mp[i-1][n+1]&&j+k-1>=mp[i-1][n+2])tem--;
if(mp[i+k-1][n+1]!=-1&&j<=mp[i+k-1][n+1]&&j+k-1>=mp[i+k-1][n+2])tem++;
add_r[i][j]=add_r[i-1][j]+tem;
}
}
}
int sum=0;
for(int i=1;i<=n;i++){
if(mp[i][n+1]==-1)sum++;
if(mp[n+1][i]==-1)sum++;
}
int maxx=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
maxx=max(sum+add_c[i][j]+add_r[i][j],maxx);
}
}
printf("%d",maxx);
#ifdef DEBUG
printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
#endif
//cout << "Fuck You !" << endl;
return 0;
}