codeforces 1200 D. White Lines(二维尺取)

https://codeforces.com/contest/1200/problem/D
题意:给出一个n*n的由BW组成的点阵,有一个橡皮擦可以使左上角为x,y,边长为k的矩阵中B变成W,通过一次操作使得行和列全为w的数量最多,求出这个数量

思路:时间复杂度肯定为O(n2),所以考虑如何枚举每个点的同时就能直接求出每个点的贡献。
首先满足一行在这个方块内时,需要最左边方块和最右边方块都在内部。
一列在方块内时,需要最上面和最下面方块在内部

当我们每次向右边移动一列时,我们这个方块,最左边会出去一列,右边会进来一列,那么列的贡献只需要O(1)判断,如果左边原来有cnt–,右边进来cnt++,一开始通过k2计算出来初始矩阵的贡献,但是行的贡献需要O(K) 显然不能同时计算行列的贡献,所以直接分开计算行列贡献,最后判断行列贡献值最大即可
注意如果一开始未操作时就全为W,不进入cnt计算

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
using namespace std;
 
typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, int> LP;
const int inf = 0x3f3f3f3f;
const int N = 2e3 + 100;
const int mod = 10007;
const int base=131;
tr1::unordered_map<ll,ll> mp;
 
char s[2005][2005];
int n,k;
bool row[2005],col[2005];
int l[N],r[N],up[N],dw[N];
int cnt,x,y;
int a[N][N],b[N][N];
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++)
	{
		int flag=0;
		for(int j=1;j<=n;j++)
			if(s[i][j]=='B')
			{
				flag=1;
				if(!l[i]) l[i]=j;
				r[i]=j;
			}
		if(flag==0) row[i]=1,x++;
 
		flag=0;
		for(int j=1;j<=n;j++)
			if(s[j][i]=='B')
			{
				flag=1;
				if(!up[i]) up[i]=j;
				dw[i]=j;
			}
		if(flag==0) col[i]=1,y++;
		//if(row[i]||col[i]) cout<<i<<endl;
	}
 
	for(int j=1;j+k-1<=n;j++)
	for(int i=1;i+k-1<=n;i++)
	{
		if(i==1)
		{
			cnt=x;
			for(int c=1;c<=k;c++)
			{
				if(row[c]) continue;
				if(l[c]>=j&&r[c]<=j+k-1) cnt++;
			}
			a[i][j]=cnt;
		}
		else
		{
			if(!row[i-1])
			{
				if(l[i-1]>=j&&r[i-1]<=j+k-1) cnt--;
			}
			if(!row[i+k-1])
			{
				if(l[i+k-1]>=j&&r[i+k-1]<=j+k-1) cnt++;
			}
			a[i][j]=cnt;
		}
	}
 
 
 
	for(int i=1;i+k-1<=n;i++)
	for(int j=1;j+k-1<=n;j++)
	{
		if(j==1)
		{
			cnt=y;
			for(int c=1;c<=k;c++)
			{
				if(col[c]) continue;
				if(up[c]>=i&&dw[c]<=i+k-1) cnt++;
			}
			b[i][j]=cnt;
		}
		else
		{
			if(!col[j-1])
			{
				if(up[j-1]>=i&&dw[j-1]<=i+k-1) cnt--;
			}
			if(!col[j+k-1])
			{
				if(up[j+k-1]>=i&&dw[j+k-1]<=i+k-1) cnt++;
			}
			b[i][j]=cnt;
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		ans=max(ans,a[i][j]+b[i][j]);
	printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值