【PA】PA2014Final Wykładzina【单调栈+双指针+均摊分析】

题目链接:【PA】PA2014Final Wykładzina

题目大意:给一个 NM 01 矩阵,最多可将一个 1 修改成0,求最大全 0 子矩阵内0的个数。
题目分析:考虑对普通求最大全 0 子矩阵扩展,记录每个位置往左往右严格比他矮的最近的块的位置,然后枚举哪一列一定含1,然后往左往右跳 pre ,并且要满足每一步后至少有一个高度不低于当前列没有 1 时的高度高,均摊分析可知每一行还是O(N)的。

思路比较巧妙的简单题,复杂度 O(N2)

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;
typedef pair < int , int > pii ;
typedef unsigned long long ULL ;

#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 2005 ;

int L[MAXN] , R[MAXN] ;
int U[MAXN][MAXN] ;
int S[MAXN] , top ;
char s[MAXN] ;
int n , m ;

void solve () {
    int ans = 0 ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        scanf ( "%s" , s + 1 ) ;
        for ( int j = 1 ; j <= m ; ++ j ) {
            U[i][j] = s[j] == '.' ? U[i - 1][j] + 1 : 0 ;
        }
        S[top = 0] = 0 ;
        for ( int j = 1 ; j <= m ; ++ j ) {
            while ( top && U[i][S[top]] >= U[i][j] ) -- top ;
            L[j] = S[top] ;
            S[++ top] = j ;
        }
        S[top = 0] = m + 1 ;
        for ( int j = m ; j >= 1 ; -- j ) {
            while ( top && U[i][S[top]] >= U[i][j] ) -- top ;
            R[j] = S[top] ;
            S[++ top] = j ;
        }
        for ( int j = 1 ; j <= m ; ++ j ) {
            int u = U[i][j] ;
            if ( i - u ) u += U[i - u - 1][j] + 1 ;
            if ( !u ) continue ;
            ans = max ( ans , U[i][j] * ( R[j] - L[j] - 1 ) ) ;
            ans = max ( ans , u ) ;
            int x = j - 1 , y = j + 1 ;
            while ( U[i][x] >= U[i][j] + 1 || U[i][y] >= U[i][j] + 1 ) {
                if ( U[i][x] > U[i][y] ) {
                    ans = max ( ans , min ( u , U[i][x] ) * ( y - L[x] - 1 ) ) ;
                    x = L[x] ;
                } else {
                    ans = max ( ans , min ( u , U[i][y] ) * ( R[y] - x - 1 ) ) ;
                    y = R[y] ;
                }
            }
        }
    }
    printf ( "%d\n" , ans ) ;
}

int main () {
    while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ;
    return 0 ;
}

压缩后代码:

#include <bits/stdc++.h>
using namespace std;
#define clr(a,x) memset(a,x,sizeof a)
const int MAXN=2005;
int L[MAXN],R[MAXN],U[MAXN][MAXN],S[MAXN],t,n,m;
char s[MAXN];
void solve(){
    int ans=0,i,j,*up;
    for(i=1;i<=n;++i){
        scanf("%s",s+1);
        for(j=1,up=U[i];j<=m;++j)up[j]=s[j]=='.'?U[i-1][j]+1:0;
        for(S[t=0]=0,j=1;j<=m;L[j]=S[t],S[++t]=j++)while(t&&up[S[t]]>=up[j])--t;
        for(S[t=0]=m+1,j=m;j>=1;R[j]=S[t],S[++t]=j--)while(t&&up[S[t]]>=up[j])--t;
        for(j=1;j<=m;++j){
            int u=U[i][j],x=j-1,y=j+1;
            if(i-u)u+=U[i-u-1][j]+1;
            ans=max(ans,max(u,U[i][j]*(R[j]-L[j]-1)));
            while(up[x]>=up[j]+1||up[y]>=up[j]+1){
                if(up[x]>up[y])ans=max(ans,min(u,up[x])*(y-L[x]-1)),x=L[x];
                else ans=max(ans,min(u,up[y])*(R[y]-x-1)),y=R[y];
            }
        }
    }
    printf("%d\n",ans);
}
int main(){
    while(~scanf("%d%d",&n,&m))solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值