二维差分前缀和——cf1202D(好题)

直接枚举每个点作为左上角是可以做的,但是写起来较麻烦

有一种较为简单的做法是对一列或一行统计贡献

比如某一行的B存在的区间是L,R那么就有三种情况

  1.没有这样的区间,即一行都是W,此时这行对答案的贡献一直是1

  2.R-L+1<=k,那么这一段必须要找一个点代表的矩形来覆盖,可以求出这样的点的存在区间是一个矩形,当且仅当点在这个矩形范围内时,这一行会有1的贡献、

  3.R-L+1>k,永远不会有贡献

对于情况2,我们用二维的差分来统计一下,最后枚举每个点,看我们选择这个点代表的矩形时,贡献是否达到最大就行

#include<bits/stdc++.h>
using namespace std;
#define N 2005
char mp[N][N];
int n,k,tot,l[N],r[N],u[N],d[N],cnt[N][N];
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("\n%c",&mp[i][j]);
    
    memset(l,0x3f,sizeof l);
    memset(u,0x3f,sizeof u);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
            if(mp[i][j]=='B')
                l[i]=min(l[i],j),r[i]=max(r[i],j);
        if(l[i]==0x3f3f3f3f)
            tot++;
        else if(r[i]-l[i]+1<=k){
            int x1=max(1,i-k+1),y1=max(1,r[i]-k+1);
            int x2=i,y2=l[i];
            cnt[x1][y1]++;cnt[x1][y2+1]--;
            cnt[x2+1][y1]--;cnt[x2+1][y2+1]++;
        }
    }
    for(int j=1;j<=n;j++){
        for(int i=1;i<=n;i++)
            if(mp[i][j]=='B')
                u[j]=min(u[j],i),d[j]=max(d[j],i);
        if(u[j]==0x3f3f3f3f)
            tot++;
        else if(d[j]-u[j]+1<=k){
            int x1=max(1,d[j]-k+1),y1=max(1,j-k+1);
            int x2=u[j],y2=j;
            cnt[x1][y1]++;cnt[x1][y2+1]--;
            cnt[x2+1][y1]--;cnt[x2+1][y2+1]++;
        }
    }
    
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            cnt[i][j]+=cnt[i-1][j]+cnt[i][j-1]-cnt[i-1][j-1];
            ans=max(ans,cnt[i][j]);
        }
    cout<<ans+tot<<endl;
    
}

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/11518012.html