CF1200D 【White Lines】

退役快一年了之后又打了场紧张刺激的$CF$(斜眼笑)

然后发现$D$题和题解里的大众做法不太一样 (思路清奇)

题意不再赘述,我们可以看到这个题~~好做~~在只有一次擦除机会,尝试以此为突破口解决问题

我们考虑擦除某一行(列同理),分别记录这一行最左端和最右端的黑块位置(分别记为$l,r$)

这里存在以下三种情况:

1,这一行没有黑块,这时无论在哪擦除,这一行必然全白,记录答案后不再考虑

2,这一行的最左黑块和最右黑块之间的距离$>k$(即$r-l+1>k$),这时无论在哪擦除,这一行必然不会全白,不再考虑

3,这一行最左黑块和最右黑块之间的距离$<=k$,考虑能够使得这一行全为白色的擦除位置(假设我们当前考虑的是第$i$行)

容易得出,对于擦除位置的选择

可行的行:第$i-k+1((i-k+1)+k-1=i)$行到第$i$行

可行的列:第$l-k+1((l-k+1)+k-1=l)$列到第$l$列

即如果擦除位置$(x,y)$满足$i-k+1<=x<=i$且$l-k+1<=y<=l$,这一次擦除可以使第$i$行变白

对于答案统计,自然想到二维前缀和

我们只需在位置$(i-k+1,l-k+1),(i+1,l+1)+1$,$(i-k+1,l+1),(i+1,l-k+1)-1$即可(二维差分的常规操作)

差分完了再做前缀和即可得出答案(别忘了累加情况一的答案)

$P.S.i-k+1$和$l-k+1$不要数组越界

上代码:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=2010;
int n,k,ans[maxn][maxn],l[2][maxn],r[2][maxn],res,bs;
bool exi[maxn][maxn];
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        string s;
        cin>>s;
        for(int j=0;j<n;j++)
            if(s[j]=='W')
                exi[i][j+1]=0;
            else
                exi[i][j+1]=1;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            if(exi[i][j])
            {
                l[0][i]=j;
                break;
            }
        for(int j=n;j;j--)
            if(exi[i][j])
            {
                r[0][i]=j;
                break;
            }
        if(!l[0][i])
            bs++;
    }
    for(int j=1;j<=n;j++)
    {
        for(int i=1;i<=n;i++)
            if(exi[i][j])
            {
                l[1][j]=i;
                break;
            }
        for(int i=n;i;i--)
            if(exi[i][j])
            {
                r[1][j]=i;
                break;
            }
        if(!l[1][j])
            bs++;
    }
    for(int i=1;i<=n;i++)
    {
        if(l[0][i]&&r[0][i]-l[0][i]+1<=k)
        {
            int minx=max(i-k+1,1),miny=max(1,r[0][i]-k+1);
            ans[minx][miny]++;
            ans[i+1][miny]--;
                ans[minx][l[0][i]+1]--;
                ans[i+1][l[0][i]+1]++;
        }
        if(l[1][i]&&r[1][i]-l[1][i]+1<=k)
        {
            int miny=max(i-k+1,1),minx=max(1,r[1][i]-k+1);
            ans[minx][miny]++;
            ans[minx][i+1]--;
                ans[l[1][i]+1][miny]--;
                ans[l[1][i]+1][i+1]++;
        }
    }
    for(int i=1;i<=n-k+1;i++)
        for(int j=1;j<=n-k+1;j++)
        {
            ans[i][j]+=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];
            res=max(res,ans[i][j]);
        }
    printf("%d\n",res+bs);
    return 0;
}

 

posted @ 2019-08-12 17:37  Ivanovcraft  阅读(236)  评论(0编辑  收藏  举报