爆零好爽,被中学生虐好爽,还好我毕业得早

  求全1(或全0)子矩阵的个数,看了题解有好几种思路,我学了三种,但有两种不是很理解,而且也没另外那个跑得快,所以简单讲述一一下我会的那种来自Caro23333大佬的思路,传送门。

  首先我们要知道,n*m矩阵的全部子矩阵的个数是C2n+1*C2m+1,因为n*m矩阵横的线就有n+1条,竖的线就有m+1条,而我们横的线任选两根,竖的线也任选两根就能组成一个矩阵了。我们求解的思路就是用总的矩阵数去减去不是全0(或者全1)的子矩阵数。那怎么去求出不是全0(或者全1)的子矩阵数?

  n*m的矩阵,以(n,m)格子作为右下角的子矩阵就有n*m个,因为它的左上角可以在n*m个格子里任意取。现在我们要求不是全0(或者全1)的子矩阵数,那么就是看那些格子作为它的左上角,使得矩阵包含0(或者1)。

  就比如上图,假设涂绿色的格子为0,其他全为1,现在我们求以红色格子为右下角,不是全1的子矩阵数。那么我们发现,以绿色区域内的格子作为左上角的子矩阵就不是全1的,因为他们的右下方存在着一个0。而绿色区域也很好求,假设一个绿色点是(x,y)那相应的绿色区域就是x*y。不过我们可以看出,绿色区域会有重复,这样的话会把一个区域算了多遍,那怎么处理这个重复的区域呢?

  单调栈!我们从上到下,从左到右遍历所有格子,维护maxh[i]为i这一列为0的格子的最大行数,那么我们单调栈维护i,j,i<j有maxa[i]<maxa[j]。严格单调递减的栈,这样的话就使得,当前格子是0的话覆盖的区域不会与前面的重复,因为

  当遍历到,(4,4)这个格子的时候,maxh[4]=4,然后栈顶保持的是2,maxh[2]=3,所以把2弹出栈,这时栈顶元素是0,对(4,4)这个右下角产生贡献的绿色区域就是,res[0]+(4-0)*maxh[4],从图中看就是第二个绿色区域。

  而当这个情况时,还是遍历到(4,4)这个格子的时候,maxh[4]=3,然后栈顶保持的是2,maxh[2]=4,所以2不用弹出栈,这时栈顶元素是2,对(4,4)这个右下角产生贡献的绿色区域就是res[2]+(4-2)*maxh[4]。从图中看就是,第一个绿色区域,以及第二个绿色区域不和第一个绿色区域重复的格子数。

  所以可以知道res是什么了,res[i]就是前i列最下面的那个0能够贡献的格子,也是覆盖的区域,那么res[i]=res[栈顶元素]+(j-栈顶元素)*maxh[i]//相当于宽乘高,当遍历第i行第j列时的res[j]就是(i,j)这个格子作为右下角时,不是全1的子矩阵的左上角个数。

P3400仓鼠窝

 1 #include<cstdio>
 2 typedef long long ll;
 3 const int N=3233;
 4 int a[N][N],sta[N],maxh[N];
 5 ll res[N];
 6 int main()
 7 {
 8     int n,m;
 9     scanf("%d%d",&n,&m);
10     for(int i=1;i<=n;i++)
11         for(int j=1;j<=m;j++)
12             scanf("%d",&a[i][j]);
13     int top;
14     ll all=(1ll*n*(n+1)*m*(m+1))>>2,ans=0ll;//all总的方案数
15     for(int i=1;i<=n;i++)
16     {
17         sta[top=0]=0;
18         for(int j=1;j<=m;j++)
19         {
20             if(!a[i][j])//因为我们要求的是全1,所以维护这一列0的最大行数,也就是高度
21                 maxh[j]=i;
22             while(top&&maxh[sta[top]]<=maxh[j])
23                 top--;
24             res[j]=res[sta[top]]+1ll*(j-sta[top])*maxh[j];
25             ans+=res[j];
26             sta[++top]=j;
27         }
28     }
29     printf("%lld\n",all-ans);
30     return 0;
31 }

单调栈哦

P5300 [GXOI/GZOI2019]与或和

  这题就是把数拆成31位,每一位有对应的权值。

 1 #include<cstdio>
 2 typedef long long ll;
 3 const int N=1108,mod=1000000007;
 4 int n,cf2[32]={1},a[N][N],h[N][N];
 5 int sta[N],maxh[N];
 6 ll res[N];
 7 ll count(int k,int x)
 8 {
 9     for(int i=1;i<=n;i++)
10         maxh[i]=0;
11     int top=0;
12     ll ans=0;
13     for(int i=1;i<=n;i++)
14     {
15         sta[top=0]=0;
16         for(int j=1;j<=n;j++)
17         {
18             if(a[i][j]&cf2[k])
19                 h[i][j]=x;
20             else
21                 h[i][j]=x^1;
22             if(!h[i][j])
23                 maxh[j]=i;
24             while(top&&maxh[sta[top]]<=maxh[j])
25                 top--;
26             res[j]=res[sta[top]]+1ll*(j-sta[top])*maxh[j];
27             if(res[j]>=mod)
28                 res[j]-=mod;
29             ans+=res[j];
30             if(ans>=mod)
31                 ans-=mod;
32             sta[++top]=j;
33         }
34     }
35     return ans;
36 }
37 int main()
38 {
39     for(int i=1;i<=30;i++)
40         cf2[i]=cf2[i-1]<<1;
41     scanf("%d",&n);
42     for(int i=1;i<=n;i++)
43         for(int j=1;j<=n;j++)
44             scanf("%d",&a[i][j]);
45     ll all=((1ll*n*(n+1)*n*(n+1))>>2)%mod;
46     ll ans1=0,ans2=0;
47     for(int k=0;k<=30;k++)
48     {
49         ans1+=((all-count(k,1)+mod)%mod)*1ll*cf2[k];
50         if(ans1>=mod)
51             ans1%=mod;
52         ans2+=count(k,0)*1ll*cf2[k];
53         if(ans2>=mod)
54             ans2%=mod;
55     }
56     printf("%lld %lld\n",ans1,ans2);
57     return 0;
58 }

单调栈哦哦

转载于:https://www.cnblogs.com/LMCC1108/p/10876712.html

单调栈求全1(或全0)子矩阵的个数 洛谷P5300与或和 P3400仓鼠窝相关推荐

  1. 洛谷P3400 仓鼠窝(单调栈)

    P3400 仓鼠窝 题目描述 萌萌哒的Created equal是一只小仓鼠,小仓鼠自然有仓鼠窝啦. 仓鼠窝是一个由n*m个格子组成的行数为n.列数为m的矩阵.小仓鼠现在想要知道,这个矩阵中有多少个子 ...

  2. 洛谷10月月赛Round.1| P3400 仓鼠窝[单调栈]

    题目描述 萌萌哒的Created equal是一只小仓鼠,小仓鼠自然有仓鼠窝啦. 仓鼠窝是一个由n*m个格子组成的行数为n.列数为m的矩阵.小仓鼠现在想要知道,这个矩阵中有多少个子矩阵!(实际上就是有 ...

  3. 计算矩阵中全1子矩阵的个数

    前言 最近被我大哥安利了一道算法题, 这道题说难, 还不至于我做不出来, 说简单吧, 我还想不到最优解, 等把最优解告诉我之后, 我还正好能理解. 我甚至曾经怯怯的认为, 这题就是我哥专门给我找的, ...

  4. P3400 仓鼠窝 (单调栈 dp

    添加链接描述 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e3+9; l ...

  5. P3400 仓鼠窝 (单调栈 dp O(n*m

    添加链接描述 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e3+9; l ...

  6. HDU 6052 To my boyfriend(容斥+单调栈)

    题意:对于一个n*m的方格,每个格子中都包含一种颜色,求出任意一个矩形包含不同颜色的期望. 思路: 啊啊啊啊啊,补了两天,总算A了这道题了,简直石乐志,前面的容斥还比较好写,后面的那个>13那个 ...

  7. LibreOJ - 3083 与或和(单调栈+位运算)

    题目链接:点击查看 题目大意:给出一个 n∗mn*mn∗m 的矩阵,求所有子矩阵的"按位与和"和"按位或和" 题目分析:通过样例一的提示,不难想到拆位之后原矩阵 ...

  8. fzoj Problem 2190 非提的救赎 【单调栈】

    题目链接:fzoj Problem 2190 非提的救赎 Problem 2190 非提的救赎 Accept: 106 Submit: 312 Time Limit: 1000 mSec Memory ...

  9. cv1159 最大全0子矩阵(极大子矩阵)

    题目描述 Description 在一个01方阵中找出其中最大的全0子矩阵,所谓最大是指0的个数最多. 输入描述 Input Description 输入文件第一行为整数N,其中1<=N< ...

最新文章

  1. 牛逼!大神用漫画带你了解 Linux 内核到底长啥样
  2. 酷狗kuGoo 2007 和 flex有冲突
  3. opencv 直方图反向投影
  4. 【渝粤教育】广东开放大学 动画概论 形成性考核 (44)
  5. 计算机组成原理知识点白中英,计算机组成原理重点整理(白中英版) 考试必备
  6. Linux(Ubuntu) lib 缺失问题
  7. jmeter压测、操作数据库、分布式、 linux下运行的简单介绍
  8. Linux C入门之路,Linux C++学习之路
  9. 自带python库的环境软件_pyenv虚拟环境管理python多版本和软件库
  10. 我可以在CSS中使用onclick效果吗?
  11. pycharm 没有 python template languages_开发效率神器说说Pycharm的骚操作
  12. java arraylist删除元素_java集合类ArrayList操作之删除remove某些元素的案例分析
  13. LeetCode经典算法精解-字符串编辑距离
  14. 安装centos7 Minimal后 开启远程SSH
  15. docker 中文目录及文件乱码_解决docker容器中文乱码,修改docker容器编码格式
  16. 史上最详细JavaScript视频教程
  17. 码农小汪之理解Java注解。
  18. 【qduoj】【yzm10与大富翁的故事】(hdu百度之星)
  19. Convolution1D与Convolution2D区别
  20. bing重定向次数过多怎么办?新必应用不了了?只需一个小软件就可以轻松免费解决!

热门文章

  1. DBA主宰一切请求,MySQL 查询重写
  2. Spring Cloud Eureka 源码分析(一) 服务端启动过程
  3. DPM 2012 R2恢复Exchange 2013单用户邮箱
  4. 第一章 Spring的简单剖析
  5. JavaScript实现继承的方式
  6. CentOS查看系统信息命令和方法
  7. 优秀的程序员都应当知道的11个警句
  8. 【ExtJs】获取grid选中的records
  9. 用cxf编写基于spring的webservice之上篇
  10. 远程桌面,此计算机无法连接到远程计算机