标签:开区 top pre ref ret empty ons 出栈 sum
先回忆一下单调栈:
解决如下问题:一个点可以向右延伸和向左延伸的最大值,
维护一个单增的栈,那么对于栈里的元素a来说,右边的元素都能向右延伸的,
左边的元素都不能延伸,如果说一个要进来的元素破坏了单调性,那么我就一直pop
最后一个pop的元素实际上就是 这个要入栈的元素能向左延伸的最大长度,那么维护一下
最后push进去这个元素的向左延伸的最大值,然后队尾push-1,让他们全出栈;
解法:将每个矩形扩充出来,满足 if(x==1)h[i][j]=h[i-1][j]+1; else h[i][j]=0;这样就转换成了求最大矩形面积问题;
那注意push-1使得栈中元素全部出栈即可。
#include<cstdio> #include<cstring> #include<stack> using namespace std; typedef long long ll; const int N=2e3+5; int h[N][N]; int main(){ int n,m; while(~scanf("%d %d",&n,&m)){ memset(h,0,sizeof h); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int x; scanf("%d",&x); if(x==1)h[i][j]=h[i-1][j]+1; else h[i][j]=0; } h[i][m+1]=-1; } int ans=0,tmp,t; for(int i=1;i<=n;i++){ stack<int>stk; for(int j=1;j<=m+1;j++){ if(stk.empty()||h[i][j]>=h[i][stk.top()])stk.push(j); else { while(!stk.empty()&&h[i][j]<h[i][stk.top()]){ t=stk.top(); stk.pop(); tmp=(j-t)*h[i][t]; if(tmp>ans)ans=tmp; } stk.push(t); h[i][t]=h[i][j]; } } } printf("%d\n",ans); } return 0; }
题意:给你一个n,m,一个长度为n的01串,有m个1,问你怎么弄,使得有1的区间数最大;
解法:这题偏思维,你直接想1的区间不好想,转换为求全为0的区间,
拿总和-全为0的就是了,问题为n-m个0放到m+1个区间,怎么放;
先令 cnt1=(n-m)/(m+1),表示每个区间的平均0,
然后 cnt2=(n-m)%(m+1),表示剩余的0,那剩余的0怎么放呢?
开始我想放在两边,但这样是不对的,应该继续插在中间的区间放,
那这样的话 中间区间数为 getsum(cnt1)*(m+1)
加上剩余的 cnt2*(cnt1+1);
这算是正难则反的思想的体现吧;主要是没想到分开区间来放。
#include<cstdio> #include<cstring> #include<stack> using namespace std; typedef long long ll; const int N=2e3+5; ll getsum(ll x){return x*(x+1)/2;} int main(){ int t; scanf("%d",&t); while(t--){ ll n,m; scanf("%lld %lld",&n,&m); ll tot=getsum(n); ll cnt1=(n-m)/(m+1); ll cnt2=(n-m)%(m+1); ll ans=tot-getsum(cnt1)*(m+1)-cnt2*(cnt1+1); printf("%lld\n",ans); } return 0; }
HZNU Training 2 for Zhejiang Provincial Competition 2020
标签:开区 top pre ref ret empty ons 出栈 sum
原文地址:https://www.cnblogs.com/littlerita/p/12420147.html