闲的没事儿才写博客的死鸽子
这道题为P5300埋下了很好的伏笔qwq解法是差不多的。
一个矩阵里面的子矩阵有多少个很好求
如果加上了一些限制,我们就要重新考虑。
第一个逻辑是把大问题变成小问题
比如合法子矩阵数等于以每个点为右下角的合法子矩阵数和。
第二个逻辑是继承先前答案不重复计算
使用铅垂高思想,记录每个点向上能到达的第一个非法点位置。
如果当前点的合法点比继承点小(也就是高),那我可以完整的继承之前的答案。
比如说图中(4,4)不可以继承(4,3),(4,5)可以继承(4,4);
反之,有些子矩阵我就到不了。
也就是说,我们需要一个数据结构来维护这个合法点序列,使得任何时候序列头头都比当前点大(也就是矮)。
看起来就是一个单调栈了。
所以对于每一排重新维护单调栈,继承上一个答案的同时,计算当前答案。由于中间被踢出去的合法点都比当前点小(也就是高),我们就一定可以把腿别过去(??)
加起来即可。
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
int sta[3005],top;
int height[3005],mapp[3005][3005],ans[3005],sum;
int n,m;
signed main(){
n=in;m=in;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
mapp[i][j]=in;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!mapp[i][j])height[j]=i;
while(top&&height[sta[top]]<height[j])top--;
sta[++top]=j;
ans[top]=ans[top-1]+(j-sta[top-1])*(i-height[j]);
sum+=ans[top];
}
top=0;
}
cout<<sum;
return 0;
}
既然我们连写博客这种闲的没事儿的事情都做了
那就顺手把5300做了吧。