CodeForces 1200D White Lines

cf題面數組

  • Time limitapp

    1500 mside

  • Memory limit優化

    262144 kBthis

解題思路

官方題解spa

1200D - White Lines

Let's consider a single row that contains at least one black cell. If the first appearance of a black cell is at the l -th column and the last appearance of a black cell is at the r -th column, we can determine whether it becomes a white line when a certain cell ( i , j ) is clicked in O ( 1 ) , after some preprocessing. It becomes a white line if and only if a cell ( i , j ) is clicked where the row is at [ i , i + k 1 ] and j l r j + k 1 . We just need to compute l and r in advance..net

Now let's consider all n rows (not columns). First, count all rows that are already white lines before clicking. Then we count the number of white rows when the cell ( 1 , 1 ) is clicked, by applying the above method to all rows from 1 to k . Ignore the already-white rows that we counted before. So far we obtained the number of white rows when the cell ( 1 , 1 ) is clicked. From now, we slide the window. Add the k + 1 -st row and remove the 1 -st row by applying the same method to them, and we obtain the number of white rows when the cell ( 2 , 1 ) is clicked. We can repeat this until we calculate all n k + 1 cases for clicking the cells at the 1 -st column. Then we repeat the whole process for all n k + 1 columns.指針

The same process can be done for counting white columns, too. Now we know the number of white rows and white columns when each cell is clicked, so we can find the maximum value among their sums.code

Time complexity: O ( n 2 ) xml

能夠說是十分暴力了,cf上打的標籤有brute force。一個優化就是把橡皮覆蓋的區域一格一格地移動,這樣就能夠\(O(1)\)更新邊界了,(忽然想到滑動窗口,雖然和這題關係不大)。還有個標籤是尺取法,好像也沒毛病,滑動區域,更新邊界,這確實能夠算簡化的尺取或者雙指針吧……

另外,因爲滑動區域的時候,左右滑只能快速更新空白列數,不能快速更新空白行數,上下滑同理,因此行和列分開處理,各自來一遍

感想

原本這題沒有必要寫博客的,但太興奮了,真的。寫完代碼,改好CE之後,樣例一遍過,半信半疑交上去,竟然就AC了!

回想暑假集訓這一個月,蠢得跟啥使得,集訓題的作題記錄,一樣是一片綠,別人的就一個AC時間,個人除了AC時間,下方全都有「-1」「-2」「-3」(失敗的提交次數)……每一個小錯都要浪費我至少兩個小時……好幾回花半天時間,找到了諸如continue寫成return、數組下標或者變量寫錯之類的錯,太憋屈了…………

源代碼

#include<cstdio>
#include<algorithm>
int n,k;
const int MAXN=2e3+4;
int u[MAXN],d[MAXN],l[MAXN],r[MAXN];

int ansrow[MAXN][MAXN],anscol[MAXN][MAXN],wrow,wcol;

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        char s[2010];
        scanf("%s",s+1);
        for(int j=1;j<=n;j++)
        {
            if(s[j]=='B')
            {
                r[i]=j;
                if(!l[i]) l[i]=j;
                d[j]=i;
                if(!u[j]) u[j]=i;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(u[i]==0) wcol++;
        if(l[i]==0) wrow++;
    }
    //先是列
    for(int i=1;i+k-1<=n;i++)//對於每一行
    {
        for(int ii=1;ii<=k;ii++)//統計每行開頭區域的答案
            if(d[ii]&&d[ii]<=i+k-1&&u[ii]>=i) anscol[i][1]++;
        for(int j=2;j+k-1<=n;j++)//將統計區域向右滑動
        {
            anscol[i][j]=anscol[i][j-1];
            if(d[j-1]&&d[j-1]<=i+k-1&&u[j-1]>=i) anscol[i][j]--;
            if(d[j+k-1]&&d[j+k-1]<=i+k-1&&u[j+k-1]>=i) anscol[i][j]++;
        }
    }
    //而後行也來一遍
    for(int i=1;i+k-1<=n;i++)
    {
        for(int ii=1;ii<=k;ii++)//統計每列開頭區域的答案
            if(r[ii]&&r[ii]<=i+k-1&&l[ii]>=i) ansrow[1][i]++;
        for(int j=2;j+k-1<=n;j++)//將統計區域向下滑動
        {
            ansrow[j][i]=ansrow[j-1][i];
            if(r[j-1]&&r[j-1]<=i+k-1&&l[j-1]>=i) ansrow[j][i]--;
            if(r[j+k-1]&&r[j+k-1]<=i+k-1&&l[j+k-1]>=i) ansrow[j][i]++;
        }
    }
    int ans=-1;
    for(int i=1;i+k-1<=n;i++)
    {
        for(int j=1;j+k-1<=n;j++)
            ans=std::max(ans,anscol[i][j]+ansrow[i][j]);
    }
    printf("%d\n",ans+wcol+wrow);
    return 0;
}
相關文章
相關標籤/搜索