zoukankan      html  css  js  c++  java
  • 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
    ",res+bs);
        return 0;
    }
  • 相关阅读:
    「题解」:07.16NOIP模拟T1:礼物
    「题解」:07.16NOIP模拟T2:通讯
    「题解」:图论专题总结
    07.07NOIP模拟赛
    [复习]平衡树splay
    「题解」:[组合数学][DP]:地精部落
    「题解」:[组合数学]:Perm 排列计数
    「题解」:[组合数学]:排队
    dp 杂题
    插头 dp 总结
  • 原文地址:https://www.cnblogs.com/ivanovcraft/p/11341515.html
Copyright © 2011-2022 走看看