CFGYM103104I-WHUPC I Sequence

题意:有个$n\times n,n\leq 5000$的矩阵,挖掉$m,m\leq 10^6$个格子,问不包括这些格子的子矩阵个数。

做法很容易考虑:枚举一行,这一行从左往右扫,依次计算每个格子为右下角的子矩阵个数。

扫的时候维护一个单调栈,里面存(元素,以这个元素为高度的格子最长向右延伸了多少格)

为什么要存第二个项呢?我们维护的单调栈里面,每个东西实际上表示的是一个矩形,含义是:在我们处理完当前这个列后,这些矩形里的元素都可以作为合法的子矩阵左上顶点。

扫的时候维护一个东西:单调栈里所有矩形的大小和$sum$,即合法的左上顶点个数。

每次加入一个元素$x$,分以下三种情况讨论:

  • $x$大于单调栈最后的元素:直接加入。长度记为1,sum加上$x$(显然多了这么多合法的格子)
  • $x$等于单调栈最后的元素:单调栈最后的元素的长度加1,sum加上$x$
  • $x$小于单调栈最后的元素:弹出单调栈最后的元素,并把其长度加到倒数第二个元素上,然后重复这三个check

最后我们每插入一个元素后,所维护的sum就是以这个点为右下角的答案。

另外有一个坑:输入1625 0,答案输出正确,但是从1626 0开始,答案越来越小,看起来像是溢出了,但是开-fsanitize=undefined没报任何问题,结果最后查出来了,算一行的答案时使用的是std::accumlate,初始值传的是int类型,而后累加变量自动推导为int,导致这个函数里面溢出了,然后由于ubsan并不会对包含的其他文件的代码做检查,于是挂掉了。

 

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据