• 棋盘制作[ZJOI2007]


      题目传送门:https://www.luogu.org/problemnew/show/P1169

    题目描述

    国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。

    而我们的主人公小Q,正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则。

    小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。

    不过小Q还没有决定是找一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。

    于是小Q找到了即将参加全国信息学竞赛的你,你能帮助他么?

    输入输出格式

    输入格式:

    包含两个整数N和M,分别表示矩形纸片的长和宽。接下来的N行包含一个N * M的01矩阵,表示这张矩形纸片的颜色(0表示白色,1表示黑色)。

    输出格式:

    包含两行,每行包含一个整数。第一行为可以找到的最大正方形棋盘的面积,第二行为可以找到的最大矩形棋盘的面积(注意正方形和矩形是可以相交或者包含的)。

    输入输出样例

    输入样例#1: 
    3 3
    1 0 1
    0 1 0
    1 0 0
    
    输出样例#1: 
    4
    6
    

    说明

    对于20%的数据,N, M ≤ 80

    对于40%的数据,N, M ≤ 400

    对于100%的数据,N, M ≤ 2000

     

     题解:

      第一眼这题只会暴力qwq

      正方形复杂度O(n^5),矩形O(n^6)。这是裸暴力,剪枝剪得好会快很多。

     正解:

      先分类讨论棋盘情况,一种是左上角为1时,剩下棋盘的合法情况;另一种是左上角为0时,剩下棋盘的合法情况。这么做有什么好处呢?

      这样的话就可以看做是一个n*m的格子上有若干个障碍点,问最大不覆盖障碍点的子矩形大小。

      那这不就跟玉蟾宫这道题一模一样了吗qwq

      至于正方形,也可以类比矩形来做,具体留给大家思考。(或者看下面的代码qaq

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stack>
     6 #define LL long long
     7 #define RI register int
     8 using namespace std;
     9 const int INF = 0x7ffffff ;
    10 const int N = 2000 + 10 ;
    11 
    12 inline int read() {
    13     int k = 0 , f = 1 ; char c = getchar() ;
    14     for( ; !isdigit(c) ; c = getchar())
    15       if(c == '-') f = -1 ;
    16     for( ; isdigit(c) ; c = getchar())
    17       k = k*10 + c-'0' ;
    18     return k*f ;
    19 }
    20 int n, m, aans = 0, ans = 0 ; int pos[N][N], hh[N][N], l[N] ;
    21 
    22 inline void solve(int now) {
    23     stack<int>s ;
    24     for(int i=1;i<=m;i++) {
    25         while(s.size() && pos[now][s.top()] >= pos[now][i]) {
    26             ans = max(ans,pos[now][s.top()]*(i-l[s.top()]-1)) ;
    27             if((i-l[s.top()]-1) >= pos[now][s.top()]) aans = max(aans,pos[now][s.top()]*pos[now][s.top()]) ;
    28             s.pop() ;
    29         } 
    30         if(s.size()) l[i] = s.top() ; else l[i] = 0 ; 
    31         s.push(i) ;
    32     }
    33     while(s.size()) {
    34         ans = max(ans,pos[now][s.top()]*(m-l[s.top()])) ;
    35         if(m-l[s.top()] >= pos[now][s.top()]) aans = max(aans,pos[now][s.top()]*pos[now][s.top()]) ;
    36         s.pop() ;
    37     } 
    38 }
    39 
    40 inline void solve1() {
    41     for(int i=1;i<=n;i++) {
    42         for(int j=1;j<=m;j++) 
    43           if(!hh[i][j]) pos[i][j] = 0 ;  else pos[i][j] = pos[i-1][j]+1 ;
    44     }
    45     for(int i=1;i<=n;i++) solve(i) ;
    46 }
    47 
    48 inline void solve2() {
    49     for(int i=1;i<=n;i++) {
    50         for(int j=1;j<=m;j++) hh[i][j] ^= 1 ;
    51     }
    52     for(int i=1;i<=n;i++) {
    53         for(int j=1;j<=m;j++) 
    54           if(!hh[i][j]) pos[i][j] = 0 ;  else pos[i][j] = pos[i-1][j]+1 ;
    55     }
    56     for(int i=1;i<=n;i++) solve(i) ;    
    57 }
    58 
    59 int main() {
    60     n = read(), m = read() ;
    61     for(int i=1;i<=n;i++)
    62       for(int j=1;j<=m;j++) {
    63            bool x = read() ;
    64            if(!((i+j)&1) && x) hh[i][j] = 1 ;
    65            else if((i+j)&1 && !x) hh[i][j] = 1 ;
    66       }
    67     solve1() ;
    68     solve2() ;
    69     printf("%d
    %d",aans,ans) ;
    70     return 0 ;
    71 }

     几个错误:

    •    第34、35行那里又用n去减了=-=,第二次了qwq
    •   solve1里发现个错误,结果solve2里没改...(solve1就是solve2贴下去的=-=) 
  • 相关阅读:
    浅谈Java中的深拷贝和浅拷贝(转载)
    浅析Java中的final关键字
    Java内部类详解
    那些年震撼我们心灵的音乐
    深入理解Java的接口和抽象类
    Java:类与继承
    Java中的static关键字解析
    Java垃圾回收机制
    java 字节流和字符流的区别 转载
    Java 输入输出流 转载
  • 原文地址:https://www.cnblogs.com/zub23333/p/8747008.html
Copyright © 2020-2023  润新知