HZNU Training 2 for Zhejiang Provincial Competition 2020

A - A

 POJ - 3494 

先回忆一下单调栈:
解决如下问题:一个点可以向右延伸和向左延伸的最大值,
维护一个单增的栈,那么对于栈里的元素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;
}
View Code

B - B

 CodeForces - 1301C 

题意:给你一个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;
}
View Code



猜你喜欢

转载自www.cnblogs.com/littlerita/p/12420147.html
今日推荐