单调栈求全1(或全0)子矩阵的个数 洛谷P5300与或和 P3400仓鼠窝
爆零好爽,被中学生虐好爽,还好我毕业得早
求全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仓鼠窝相关推荐
- 洛谷P3400 仓鼠窝(单调栈)
P3400 仓鼠窝 题目描述 萌萌哒的Created equal是一只小仓鼠,小仓鼠自然有仓鼠窝啦. 仓鼠窝是一个由n*m个格子组成的行数为n.列数为m的矩阵.小仓鼠现在想要知道,这个矩阵中有多少个子 ...
- 洛谷10月月赛Round.1| P3400 仓鼠窝[单调栈]
题目描述 萌萌哒的Created equal是一只小仓鼠,小仓鼠自然有仓鼠窝啦. 仓鼠窝是一个由n*m个格子组成的行数为n.列数为m的矩阵.小仓鼠现在想要知道,这个矩阵中有多少个子矩阵!(实际上就是有 ...
- 计算矩阵中全1子矩阵的个数
前言 最近被我大哥安利了一道算法题, 这道题说难, 还不至于我做不出来, 说简单吧, 我还想不到最优解, 等把最优解告诉我之后, 我还正好能理解. 我甚至曾经怯怯的认为, 这题就是我哥专门给我找的, ...
- P3400 仓鼠窝 (单调栈 dp
添加链接描述 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e3+9; l ...
- P3400 仓鼠窝 (单调栈 dp O(n*m
添加链接描述 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e3+9; l ...
- HDU 6052 To my boyfriend(容斥+单调栈)
题意:对于一个n*m的方格,每个格子中都包含一种颜色,求出任意一个矩形包含不同颜色的期望. 思路: 啊啊啊啊啊,补了两天,总算A了这道题了,简直石乐志,前面的容斥还比较好写,后面的那个>13那个 ...
- LibreOJ - 3083 与或和(单调栈+位运算)
题目链接:点击查看 题目大意:给出一个 n∗mn*mn∗m 的矩阵,求所有子矩阵的"按位与和"和"按位或和" 题目分析:通过样例一的提示,不难想到拆位之后原矩阵 ...
- fzoj Problem 2190 非提的救赎 【单调栈】
题目链接:fzoj Problem 2190 非提的救赎 Problem 2190 非提的救赎 Accept: 106 Submit: 312 Time Limit: 1000 mSec Memory ...
- cv1159 最大全0子矩阵(极大子矩阵)
题目描述 Description 在一个01方阵中找出其中最大的全0子矩阵,所谓最大是指0的个数最多. 输入描述 Input Description 输入文件第一行为整数N,其中1<=N< ...
最新文章
- 牛逼!大神用漫画带你了解 Linux 内核到底长啥样
- 酷狗kuGoo 2007 和 flex有冲突
- opencv 直方图反向投影
- 【渝粤教育】广东开放大学 动画概论 形成性考核 (44)
- 计算机组成原理知识点白中英,计算机组成原理重点整理(白中英版) 考试必备
- Linux(Ubuntu) lib 缺失问题
- jmeter压测、操作数据库、分布式、 linux下运行的简单介绍
- Linux C入门之路,Linux C++学习之路
- 自带python库的环境软件_pyenv虚拟环境管理python多版本和软件库
- 我可以在CSS中使用onclick效果吗?
- pycharm 没有 python template languages_开发效率神器说说Pycharm的骚操作
- java arraylist删除元素_java集合类ArrayList操作之删除remove某些元素的案例分析
- LeetCode经典算法精解-字符串编辑距离
- 安装centos7 Minimal后 开启远程SSH
- docker 中文目录及文件乱码_解决docker容器中文乱码,修改docker容器编码格式
- 史上最详细JavaScript视频教程
- 码农小汪之理解Java注解。
- 【qduoj】【yzm10与大富翁的故事】(hdu百度之星)
- Convolution1D与Convolution2D区别
- bing重定向次数过多怎么办?新必应用不了了?只需一个小软件就可以轻松免费解决!