合法矩阵的面积之和

给出一张n*m(1<=n,m<=2000)的矩阵,’.’ 代表空地,’#’ 代表障碍物,合法矩阵为内部不含障碍物的矩阵。求出所有合法矩阵的面积之和。

input
2 3
.#.
…#
output
8

input
3 3



output
100

input
3 4
…#.
#…
…#
output
40
先预处理出一个数组dp,记录每个点向上最大的合法高度。 对于每一行,维护底在这一行的矩阵的面积和。从左往右扫,利用单调栈维护高度。对于答案的更新只在pop的时候进行。如果当前列高大于栈顶,直接丢进去;如果相等
就跳过;如 果当前列高小于栈顶,就把栈顶跳出并更新:
在这里插入图片描述
如图,计算绿色部分的贡献,即计算绿色部分能使底为3,4的矩阵增加多少合法矩阵的面积。或者说本来24的举证扩大了22的绿色部分之后增加的合法矩阵的面积和是多少。
计算高度为h1+1:
宽度为x*1的矩阵可以得到:

宽度数量
1x
2x-1
…………
x1

所以总宽度为
∑i=1xi∗(x−i+1)\sum_{i=1}^x{i*(x-i+1)}i=1xi(xi+1)
=∑i=1xx∗i−∑i=1xi2+∑i=1xi==\sum_{i=1}^x{x*i}-\sum_{i=1}^x{i^2}+\sum_{i=1}^x{i}==i=1xxii=1xi2+i=1xi=
∵∑i=1xi2=x(x+1)(x∗2+1)6\because \sum_{i=1}^x{i^2}=\frac{x(x+1)(x*2+1)}{6}i=1xi2=6x(x+1)(x2+1)
∴\therefore 原式=x(x+1)(x+2)6=\frac{x(x+1)(x+2)}{6}=6x(x+1)(x+2)
高度从h1+1到h2
所以增加的总面积为
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int N = 2e3+10;

ll d[N][N];
char s[N];

struct node{
    ll h,index;
}a[N];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i = 1;i<=n;i++)
    {
        scanf("%s",s+1);
        for (int j = 1;j<=m;j++)
        {
            if (s[j] == '.') d[i][j] = d[i-1][j] + 1;
        }
    }
    ll ans = 0;
    for (int i = 1;i<=n;i++)
    {
        int len = 0;
        memset(a,0,sizeof(a));
        for (int j = 1;j<=m;j++)
        {
            int last = j;
            while (len > 0 && a[len].h > d[i][j])
            {
                ll x = j-a[len].index,h1 = max(d[i][j],a[len-1].h),h2 = a[len].h;
                last = a[len].index;
                ans += x * (x + 1) * (x + 2) / 6 * (h2 - h1) * (h1 + h2 + 1) / 2;
                len--;
            }
            if (d[i][j] == a[len].h) continue;
            a[++len].h = d[i][j];
            a[len].index = last;
        }
        while (len > 0)
        {
            ll x = m-a[len].index + 1,h1 = a[len-1].h,h2 = a[len].h;
            ans += x * (x + 1) * (x + 2) / 6 * (h2 - h1) * (h1 + h2 + 1) / 2;
            len--;
        }
    }
    cout<<ans;
    return 0;
}
已经博主授权,源码转载自 https://pan.quark.cn/s/a4b39357ea24 QueueForMcu 基于单片机实现的队列功能模块,主要用于8位、16位、32位非运行RTOS的单片机应用,兼容大多数单片机平台。 开源代码:https://.com/xiaoxinpro/QueueForMcu 一、特性 动态创建队列对象 动态设置队列数据缓冲区 静态指定队列元素数据长度 采用值传递的方式保存队列数据 二、快速使用 三、配置说明 目前QueueForMcu只有一个静态配置项,具体如下: 在文件 中有一个宏定义 用于指定队列元素的数据长度,默认是 ,可以根据需要更改为其他数据类型。 四、数据结构 队列的数据结构为 用于保存队列的状态,源码如下: 其中 为配置项中自定义的数据类型。 五、创建队列 1、创建队列缓存 由于我们采用值传递的方式保存队列数据,因此我们在创建队列前要手动创建一个队列缓存区,用于存放队列数据。 以上代码即创建一个大小为 的队列缓存区。 2、创建队列结构 接下来使用 创建队列结构,用于保存队列的状态: 3、初始化队列 准备好队列缓存和队列结构后调用 函数来创建队列,该函数原型如下: 参数说明: 参考代码: 六、压入队列 1、单数据压入 将数据压入队列尾部使用 函数,该函数原型如下: 参数说明: 返回值说明: 该函数会返回一个 枚举数据类型,返回值会根据队列状态返回以下几个值: 参考代码: 2、多数据压入 若需要将多个数据(数组)压入队列可以使用 函数,原理上循环调用 函数来实现的,函数原型如下: 参数说明: 当数组长度大于队列剩余长度时,数组多余的数据将被忽略。 返回值说明: 该函数将返回实际被压入到队列中的数据长度。 当队列中的剩余长度富余...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值