• 洛谷P3400 仓鼠窝(单调栈)


    P3400 仓鼠窝

    题目描述

    萌萌哒的Created equal是一只小仓鼠,小仓鼠自然有仓鼠窝啦。

    仓鼠窝是一个由n*m个格子组成的行数为n、列数为m的矩阵。小仓鼠现在想要知道,这个矩阵中有多少个子矩阵!(实际上就是有多少个子长方形嘛。)比如说有一个2*3的矩阵,那么1*1的子矩阵有6个,1*2的子矩阵有4个,1*3的子矩阵有2个,2*1的子矩阵有3个,2*2的子矩阵有2个,2*3的子矩阵有1个,所以子矩阵共有6+4+2+3+2+1=18个。

    可是仓鼠窝中有的格子被破坏了。现在小仓鼠想要知道,有多少个内部不含被破坏的格子的子矩阵!

    输入输出格式

    输入格式:

     

    第一行两个正整数n和m,分别表示仓鼠窝的行数n、列数m。

    接下来n行,每行m个数,每个数代表对应的格子,非0即1。若为0,表示这个格子被破坏;反之代表这个格子是完好无损的。

     

    输出格式:

     

    仅一个正整数,表示未被破坏的子矩阵的个数。

     

    输入输出样例

    输入样例#1: 复制
    3 4
    1 1 1 1
    1 0 1 1
    1 1 0 1
    输出样例#1: 复制
    26

    说明

    __本题时限2s,内存限制256M,因新评测机速度较为接近NOIP评测机速度,请注意常数问题带来的影响。__

    No    n=    m=    备注
    1    2    2    无
    2    3    3    无
    3    5    5    无
    4    10    10    无
    5    2000    2000    所有格子均未被破坏
    6    3000    3000    所有格子均未被破坏
    7    2500    3000    有且仅有一个格子被破坏
    8    3000    2500    有且仅有一个格子被破坏
    9    200    200    无
    10    500    500    无
    11    500    500    无
    12    500    500    无
    13    1000    1000    无
    14    1000    1000    无
    15    1000    1500    无
    16    2500    2500    无
    17    2500    3000    无
    18    3000    2500    无
    19    3000    3000    无
    20    3000    3000    无


    /*
    对于每个点,累加高度,看能往右扩展几步。
    单调栈实现 栈内元素是每个点能扩展的高度,单调递增
    如果当前元素的高度大于栈顶元素的高度,就可以累加宽度并入栈
    否则就出栈知道大于为止,这样才可以累加宽度
    类似这种情况
    ****  
     ***
      **
       *
    如果入栈的高度为3,那么一定不能合并第4列的宽度,因为构不成矩形。 
    每次入栈的时候合并宽度 
    pair里分别存的是高度和宽度 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 3007
    #define ll long long
    
    using namespace std;
    int n,m,k,top;
    int a[N][N],tot[N];
    ll ans,cnt;
    pair<int,int>sta[N];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
        a[i][j]=read();
        
        for(int i=1;i<=n;i++)
        {
            cnt=0;top=0;pair<int,int>tmp;
            for(int j=1;j<=m;j++)
            {
                if(a[i][j]==0)
                {
                    cnt=top=0;tot[j]=0;
                    continue;
                }
                tot[j]++;tmp.first=tot[j];tmp.second=1;
                while(top && sta[top].first>=tmp.first)
                {
                    tmp.second+=sta[top].second;//合并到一起,宽度++
                    cnt-=sta[top].first*sta[top--].second;//此部分会在下面重复计算所以减去
                }
                sta[++top]=tmp;
                cnt+=tmp.first*tmp.second;ans+=cnt;//当前结果就等于入栈的那个点的计算结果
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
     
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    婚礼珠宝策划
    Mandelbrot图像
    程序的又一次测量学实际应用(程序对全站仪测量学导出数据文件的读取与修改)
    中国海域系统源代码
    利用“三角化”计算行列式快速求解程序(验证过很多题目的,绝对准确)
    ”上三角“行列式源代码(改良版,添加了几种特殊情况的特殊处理)
    中国海域系统
    Java
    Java
    【日记】12.12
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7787916.html
Copyright © 2020-2023  润新知