(CodeForces)D. White Lines (暴力)

传送门

题意:给出一个矩阵,格子有黑白两种,同时给你一个边长为k的矩阵,你可以使得一个边长为k的矩阵变为全白,使得白线(一行全白或一列全白)的个数最多。

解:没想到什么好办法,感觉就是暴力了吧,我的想法是先处理每个点是否可以到达上界,左界,右界和下界,同时将原本存在的白线先计算了,考虑矩阵平移,考虑列,每次就增加一列,减少一列,所以我们O(1)考虑这个贡献就行了考虑行,每次下移也就增加一行减少一行,O(1)转移,所以我们只需在算第一行和第一列的时候,进行暴力计算即可。常数比较大的O(n^2).而且我这码量不小。

码量小的在下面T_T

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int maxn=2e3+5;
//il int Add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll x,int y) {return x*y>=mod?x*y%mod:x*y;}
int n,k;
int mp[maxn][maxn];
int up[maxn][maxn],down[maxn][maxn],le[maxn][maxn],ri[maxn][maxn];
bool fgud[maxn],fglr[maxn];
int init() {
	int ans=0;
	for(int i=1; i<=n; ++i) {
		bool fg1=0,fg2=0;
		for(int j=1; j<=n; ++j) {
			if(!mp[i][j]) {
				fg1=1;
				break;
			}
		}
		if(!fg1) ans++,fglr[i]=1;
		for(int j=1; j<=n; ++j) {
			if(!mp[j][i]) {
				fg2=1;
				break;
			}
		}
		if(!fg2) ans++,fgud[i]=1;
	}
	return ans;
}
void gao() {
	for(int i=0; i<=n+1; ++i) up[0][i]=1,down[n+1][i]=1,le[i][0]=1,ri[i][n+1]=1;
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=n; ++j) {
			if((up[i-1][j]==1) && mp[i][j]==1) up[i][j]=1;
			if((le[i][j-1]==1) && mp[i][j]==1) le[i][j]=1;
		}
	}
	for(int i=n; i>=1; --i) {
		for(int j=n; j>=1; --j) {
			if((down[i+1][j]==1) && mp[i][j]==1) down[i][j]=1;
			if((ri[i][j+1]==1) && mp[i][j]==1) ri[i][j]=1;
		}
	}
}
int updown[maxn];
int main() {
	std::ios::sync_with_stdio(0);
	cin>>n>>k;
	string s;
	for(int i=1; i<=n; ++i) {
		cin>>s;
		for(int j=1; j<=n; ++j) {
			if(s[j-1]=='W') mp[i][j]=1;
			else mp[i][j]=0;
		}
	}
	int ans=init();
	gao();
	int res=ans,preans=ans;
//	cout<<"pre "<<preans<<endl;
	
	for(int i=1; i+k-1<=n; ++i) {
		int nl=i,nr=i+k-1,nup=1,ndown=1+k-1;
		if(nl==1) {
			for(int j=nl; j<=nr; ++j) {
				if((up[nup-1][j]) && (down[ndown+1][j]) && !fgud[j]) ans++;
			}
			for(int j=nup; j<=ndown; ++j) {
				if((le[j][nl-1]) && (ri[j][nr+1]) && !fglr[j]) ans++,updown[i]++;
			}
			res=max(res,ans);
			ans-=updown[i];
		} else {
			if((up[nup-1][nl-1]) && (down[ndown+1][nl-1]) && !fgud[nl-1]) ans--;
			if((up[nup-1][nr]) && (down[ndown+1][nr]) && !fgud[nr]) ans++;
			for(int j=nup; j<=ndown; ++j) {
				if((le[j][nl-1]) && (ri[j][nr+1]) && !fglr[j]) ans++,updown[i]++;
			}
			res=max(res,ans);
			ans-=updown[i];
		}
	}
//	cout<<"res "<<res<<endl;
	
	for(int t=2; t+k-1<=n; ++t) {
		ans=preans;
		for(int i=1; i+k-1<=n; ++i) {
			int nl=i,nr=i+k-1,nup=t,ndown=t+k-1;
			if(nl==1) {
				for(int j=nl; j<=nr; ++j) {
					if((up[nup-1][j]) && (down[ndown+1][j]) && !fgud[j]) ans++;
				}
				if(le[nup-1][nl-1] && ri[nup-1][nr+1] && !fglr[nup-1]) updown[i]--;
				if(le[ndown][nl-1] && ri[ndown][nr+1] && !fglr[ndown]) updown[i]++;
				ans+=updown[i];
				res=max(res,ans);
				ans-=updown[i];
			}
			else{
				if(le[nup-1][nl-1] && ri[nup-1][nr+1] && !fglr[nup-1]) updown[i]--;
				if(le[ndown][nl-1] && ri[ndown][nr+1] && !fglr[ndown]) updown[i]++;
				ans+=updown[i];
				if((up[nup-1][nl-1]) && (down[ndown+1][nl-1]) && !fgud[nl-1]) ans--;
				if((up[nup-1][nr]) && (down[ndown+1][nr]) && !fgud[nr]) ans++;
				res=max(res,ans);
				ans-=updown[i];
			}
		}

	}
	cout<<res<<endl;
	return 0;
}

赛后看别人的代码,浓缩的思想呀。

r[i][j]:第i行前j出现B的个数;

c[i][j]:第i列前j出现B的个数;

rr[i][j]:  前i行第j个矩阵(i,j为左顶点),新产生的白线 的前缀和

cc[i][j]: 前j列的第i个矩阵(i,j为左顶点),新产生的白线 的前缀和


#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e3 + 10;
char s[N][N];
int r[N][N],c[N][N],rr[N][N],cc[N][N];
int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    for (int i = 1; i <= n; i++)
        scanf("%s",s[i]+1);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            r[i][j] = r[i][j-1]+(s[i][j]=='B'); //i行 
            c[i][j] = c[i][j-1]+(s[j][i]=='B'); //i列 
        }
    }
    int tot = 0;
    for (int i = 1; i <= n; i++) 
        tot+=(r[i][n] == 0) + (c[i][n] == 0);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n-k+1; j++) {
            rr[i][j] = rr[i-1][j] + (r[i][j+k-1] - r[i][j-1] == r[i][n] && r[i][n]);
            cc[i][j] = cc[i-1][j] + (c[i][j+k-1] - c[i][j-1] == c[i][n] && c[i][n]);
        }
    }
    int ans = tot;
    for (int i = 1; i <= n-k+1; i++) 
        for (int j = 1; j <= n-k+1; j++)
            ans = max(ans,tot+(rr[i+k-1][j]-rr[i-1][j])+(cc[j+k-1][i]-cc[j-1][i]));
    printf("%d\n", ans);
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值