zoukankan      html  css  js  c++  java
  • 洛谷4147 玉蟾宫

    题目背景

    有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。

    题目描述

    这片土地被分成N*M个格子,每个格子里写着'R'或者'F',R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。

    现在freda要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着'F'并且面积最大。

    但是rainbow和freda的OI水平都弱爆了,找不出这块土地,而蓝兔也想看freda卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为S,它们每人给你S两银子。

    输入输出格式

    输入格式:

    第一行两个整数N,M,表示矩形土地有N行M列。

    接下来N行,每行M个用空格隔开的字符'F'或'R',描述了矩形土地。

    输出格式:

    输出一个整数,表示你能得到多少银子,即(3*最大'F'矩形土地面积)的值。

    输入输出样例

    输入样例#1:

    5 6
    R F F F F F
    F F F F F F
    R R R F F F
    F F F F F F
    F F F F F F

    输出样例#1:

    45

    说明

    对于50%的数据,1<=N,M<=200

    对于100%的数据,1<=N,M<=1000

    题解

    超时n3算法

    n^3算法很好想,首先要进行一个预处理,以样例为例:
    首先,读入之后将字符'F'设为1,'R' 设为0,那么样例处理之后效果如下:

    0 1 1 1 1 1
    1 2 2 2 2 2
    1 2 2 3 3 3
    2 3 3 4 4 4
    3 4 4 5 5 5

    然后进行n^3模拟即可,在这里不多介绍。

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<iostream>
     6 #include<algorithm>
     7 #pragma GCC optimize(1)
     8 #pragma GCC optimize(2)
     9 #pragma GCC optimize(3)
    10 #include<bits/stdc++.h>
    11 
    12 using namespace std;
    13 
    14 int n,m;
    15 int ans=-1;
    16 int a[1050][1050];
    17  
    18 void init() {
    19     char c;
    20     scanf("%d%d",&n,&m);
    21     for(int i=1; i<=n; i++)
    22         for(int j=1; j<=m; j++) {
    23             cin>>c;
    24             if(c=='F')a[i][j]=1;
    25         }
    26     for(int i=1; i<=n; i++)
    27         for(int j=1; j<=m; j++)
    28             a[i][j]+=a[i-1][j];
    29     return ;
    30 }
    31 
    32 void out() {
    33     for(int i=1; i<=n; i++) {
    34         for(int j=1; j<=m; j++)
    35             printf ("%d ",a[i][j]);
    36         cout<<endl;
    37     }
    38     return;
    39 }
    40 
    41 void work() {
    42     //out(); 
    43     for(int i=1; i<=n; ++i)
    44         for(int j=1; j<=i; j++) {
    45             int sum=0;
    46             for(int k=1; k<=m; ++k) {
    47                 if(a[i][k]-a[j-1][k]==i-j+1)
    48                     sum+=a[i][k]-a[j-1][k],ans=max(ans,sum);
    49                 else sum=0;
    50             }
    51         }
    52     cout<<ans*3<<endl;
    53     return;
    54 }
    55 
    56 int main() {
    57     init();
    58     work();
    59     return 0;
    60 }

     代码中可以看到,我同时开了O1,O2,O3优化,但是仍然没有逃脱超时的命运。

    满分算法

    我们考虑使用单调栈。关于单调栈,我推荐一篇博客:

    https://www.cnblogs.com/COLIN-LIGHTNING/p/8474668.html

    这篇博客很良心,博主是我在博客园中唯一关注的。

    那下面还是从头讲本题正解:

    1.我们按行去划分,O(n)枚举行,对该行即以上的部分做最大矩阵处理;

    2.那么我们用pos数组记录每行向上可延伸的最大距离,预处理的方式即为:

        (1)读到一个‘F’,该处a=上一行该列a的值+1;

        (2)读到一个‘R’,该处a=0(因为该处不可向上伸展);

    (以上都是n^3超时算法也要处理的)

    3.那么对于每次枚举:对该行及以上的部分从左往右或从右往左进行一次单增栈,每次弹栈时更新最大面积;

        (1)首先,该栈是单调递增的

        (2)如果入栈元素小于栈顶元素,栈顶元素就要出栈

        (3)如果入栈元素不小于栈顶元素,那么先入栈,然后计算当前的最大面积,更新本组答案。

    4.对每次枚举的最大面积取max即为最终答案;

     1 #include <stack>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 #include <bits/stdc++.h>
     7 using namespace std;
     8 
     9 const int N=1005;
    10 
    11 int n,m,ans=0;
    12 int a[N][N];
    13 stack <int> s,L;
    14 
    15 void init()
    16 {
    17     int i,j;
    18     char ch[2];
    19     scanf("%d %d",&n,&m);
    20     for (i=1; i<=n; i++)
    21         for(j=1; j<=m; j++)
    22         {
    23             scanf("%s",ch);
    24             if (ch[0]=='F')
    25                 a[i][j]=a[i-1][j]+1;//a[i][j]表示第j列从第i行往上'F'的个数(高度)
    26         }
    27 }
    28 
    29 void work(int h[])//处理到第i行
    30 {
    31     int j,len;
    32     s.push(0);//栈内保存高度
    33     L.push(0);//栈内保存宽度
    34     for(j=1; j<=m; j++)
    35         if (h[j]>=s.top())
    36         {
    37             s.push(h[j]);
    38             L.push(1);
    39         }
    40         else
    41         {
    42             len=0;
    43             while(!s.empty() && s.top()>h[j])//高度栈保证单调递增
    44             {
    45                 len+=L.top();
    46                 ans=max(ans,len*s.top());
    47                 s.pop();
    48                 L.pop();
    49             }
    50             s.push(h[j]);
    51             L.push(len+1);
    52         }
    53     len=0;
    54     while(!s.empty())//最后计算答案
    55     {
    56         len+=L.top();
    57         ans=max(ans,len*s.top());
    58         s.pop();
    59         L.pop();
    60     }
    61 }
    62 
    63 int main()
    64 {
    65     init();
    66     for(int i=1; i<=n; i++)
    67         work(a[i]);
    68     printf("%d
    ",3*ans);
    69     return 0;
    70 }

    出处:https://www.cnblogs.com/yujustin/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    温馨提示:尽量使用版本较高的浏览器,并打开极速模式。
  • 相关阅读:
    android java epson串口打印机
    CMake交叉编译配置
    【BIRT】汉化设计器
    数据仓库理论
    【Excel】多条件查找
    【Excel】定位条件快速将空值替换为指定值
    【DataStage】使用Sequence Job报错:CopyOfseq_ld..JobControl (fatal error from @Coordinator): Sequence job (restartable) will abort due to previous unrecoverable errors
    【Excel】数据字典制作
    【PMP】关键路径法与关键链法
    【PMP】易混淆知识点
  • 原文地址:https://www.cnblogs.com/yujustin/p/11133112.html
Copyright © 2011-2022 走看看