zoukankan      html  css  js  c++  java
  • Codeforces Round #578 (Div. 2)

    D题

    题目大意:有一个N*N(1<=N<=2000)方阵,每个点非黑即白,现在可以选一个 K * K(1<=K<=N) 的子矩阵,将其中黑点全部变白,统计操作后方阵完全为白色的行的行数,完全为白色的列的列数,求二者之和最大值。

    N^2*K的暴力很好想,预处理每行每列的黑点数,以及每个点左边的黑点数,上边的黑点数,N^2跑每个点,两趟K次得到答案,然而复杂度过不了。

    问题还是出在重复计算上,如果将子矩阵看作窗口,那么该窗口的列答案在左右移动时可以被继承很多(不用重复算),行答案在上下移动时也可被继承。可将行贡献与列贡献二者分开处理,用移动窗口的思路写。

     1 #pragma optimize("O3","unroll-loops")
     2 #pragma target("avx3")
     3 
     4 #include <bits/stdc++.h>
     5 using namespace std;
     6 
     7 const int maxn = 2012;
     8 typedef pair<int , int > pii;
     9 pii LR[maxn] , UD[maxn];
    10 char raw[maxn][maxn];
    11 pii dp[maxn][maxn];
    12 
    13 inline bool COVER(pii x, pii y){// x cover y
    14     return x.first <= y.first && y.second <= x.second;
    15 }
    16 
    17 
    18 int main(){
    19     int ever  = 0;
    20     int N,K;
    21     scanf("%d%d",&N,&K);
    22     for (int i = 1; i <= N; ++i) {
    23         scanf("%s",raw[i] + 1);
    24         LR[i] = make_pair(-1,-1);
    25         bool evermeet = false;
    26         for(int j =1;j<=N;++j){
    27             if(raw[i][j] == 'B') {
    28                 LR[i].second = j;
    29                 if(!evermeet) evermeet = true, LR[i].first = j;
    30             }
    31         }
    32         if(!evermeet) ever ++;
    33     }
    34     for(int j=1;j<=N;++j){
    35         UD[j] = make_pair(-1,-1);
    36         bool evermeet = false;
    37         for(int i = 1;i<=N;++i){
    38             if(raw[i][j] == 'B'){
    39                 UD[j].second = i;
    40                 if(!evermeet) evermeet = true , UD[j].first = i;
    41             }
    42         }
    43         if(!evermeet) ever ++;
    44     }
    45     for(int i = 1;i<= N - K +1;++i){
    46         pii curUD = make_pair(i,i+K-1);
    47         for(int j = 1;j<=K;++j)
    48             if(COVER(curUD,UD[j]))
    49                 dp[i][1].first ++;
    50         for(int j = 2;j<=N - K + 1;++j){
    51             dp[i][j].first = dp[i][j-1].first;
    52             if(COVER(curUD,UD[j-1])) dp[i][j].first --;
    53             if(COVER(curUD,UD[j+K-1])) dp[i][j].first ++;
    54         }
    55     }
    56     for (int j = 1; j <= N - K + 1; j++) {
    57         pii curLR = make_pair(j,j+K-1);
    58         for(int i = 1;i<=K;++i)
    59             if(COVER(curLR,LR[i]))
    60                 dp[1][j].second ++;
    61         for(int i = 2;i<=N-K+1;++i){
    62             dp[i][j].second = dp[i-1][j].second;
    63             if(COVER(curLR,LR[i-1])) dp[i][j].second --;
    64             if(COVER(curLR,LR[i+K-1])) dp[i][j].second ++;
    65         }
    66     }
    67     int ans = ever;
    68     for(int i=1;i<=N;++i)
    69         for(int j=1;j<=N;++j)
    70             ans = max(ans,dp[i][j].first + dp[i][j].second + ever);
    71     printf("%d
    ",ans);
    72     return 0;
    73 }
    View Code

    这题有很多种处理行贡献与列贡献的方法,预处理最左最右和最高最低是一种,预处理每个点左边与上边的黑点数也行。(完全的白列白行可特殊处理记录,好写一点)关键在于滑动窗口继承之前部分答案的思想。

  • 相关阅读:
    Max History CodeForces
    Buy a Ticket CodeForces
    AC日记——字符串的展开 openjudge 1.7 35
    AC日记——回文子串 openjudge 1.7 34
    AC日记——判断字符串是否为回文 openjudge 1.7 33
    AC日记——行程长度编码 openjudge 1.7 32
    AC日记——字符串P型编码 openjudge 1.7 31
    AC日记——字符环 openjudge 1.7 30
    AC日记——ISBN号码 openjudge 1.7 29
    AC日记——单词倒排 1.7 28
  • 原文地址:https://www.cnblogs.com/Kiritsugu/p/11531100.html
Copyright © 2011-2022 走看看