题目链接:https://www.luogu.org/problem/CF1200D
题意:
分析:对每行每列单独进行分析,以行举例
对于每一行,找出最左边的黑点和最右边的黑点(可能为一个),如果不存在就先将答案+1,并跳过该行
如果两点长度大于K,则不可能有矩形满足将该行变为全白行,跳过该行
如果小于k的话,说明存在点能够将该行变为全白行,设该行为第i行的话,左右黑点纵坐标分别为l,r,我们发现坐标范围在(i-k+1,r-k+1)~(i,l)之间的点都可以将该行变为全白行
我们可以考虑用一个二维的差分数组来记录变化,diff[i][j]表示从(0,0)到(i,j)的变化值
那显然我们可以将diff[i][l]++,diff[i-k][l]--,diff[i][r-k]--,在将被多减了一次的diff[i-k][r-k]+1,然后从点(n,n)开始,向前递推,求出每个点可以变白行的值
令x=r−k+1,y=l,递推式即为:pra[i][j]=pra[i+1][j]+pra[i][j+1]−pra[i+1][j+1]+sum[i][j]
代码实现过程要注意数组越界情况
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; #define mem0(a) memset(a,0,sizeof(a)) #define meminf(a) memset(a,0x3f,sizeof(a)) #define ls rt<<1 #define rs rt<<1|1 typedef unsigned long long ull; const int maxn=150010; const int mod=1e9+7; char a[2010][2010]; int diff[2010][2010]; int pre[2010][2010]; int main(){ int n,k;scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%s",a[i]+1); } //line operation int ans=0; for(int i=1;i<=n;i++){ int l=n+1,r=0; for(int j=1;j<=n;j++){ if(a[i][j]=='B'){ l=min(l,j); r=max(r,j); } } if(l==n+1) { ans++;continue; } if(r-l>=k)continue; int x=max(1,r-k+1),y=l;//可行区域的左右边界 diff[i][y]++;diff[i][x-1]--; if(i>=k)diff[i-k][y]--,diff[i-k][x-1]++; } //row operation for(int i=1;i<=n;i++){ int u=n+1,d=0; for(int j=1;j<=n;j++){ if(a[j][i]=='B'){ u=min(u,j); d=max(d,j); } } if(u==n+1){ ans++;continue; } if(d-u>=k)continue; int x=max(1,d-k+1),y=u;//可行区域的上下边界 diff[y][i]++; diff[x-1][i]--; if(i>=k)diff[y][i-k]--,diff[x-1][i-k]++; } int res=0; for(int i=n;i>=1;i--){ for(int j=n;j>=1;j--){ pre[i][j]=pre[i+1][j]+pre[i][j+1]-pre[i+1][j+1]+diff[i][j]; res=max(res,pre[i][j]); } } printf("%d ",ans+res); return 0; }