• 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

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

  • 相关阅读:
    分布式版本控制系统Git的安装与使用
    利用GitLab自动同步软件仓库
    MakerDAO 代币解释:DAI, WETH, PETH, SIN, MKR(一)
    数组 Major^
    String 类 Major^
    深度优先排序(数字全排列) Major^
    喊数字小游戏 Major^
    java数据类型 Major^
    ArrayList类的使用方法 Major^
    深度优先搜索(迷宫救人最短路径) Major^
  • 原文地址:https://www.cnblogs.com/Kiritsugu/p/11531100.html
Copyright © 2020-2023  润新知