Puzzle Game HihoCoder - 1634(ICPC 北京 2017 H )最大子矩阵+思维

传送门:https://hihocoder.com/problemset/problem/1634

题意:给你一个n*m(n,m<=150)的数字矩阵,每个元素val(-1000<=val<=1000),以及一个数字p(-1000<=p<=1000)。你现在最多可以修改矩阵中的一个数字,改成p,求最大子矩阵的最小值

思路:其实关键还是想到,对于某个点(i,j),要么最大子矩阵(设值为ma)经过了这个点,要么没有经过这个点。如果没有经过这个点,我们只需要统计其上下左右四个部分包含的最大子矩阵,记为tmp1,如果经过这个点,就将这个点替换为p,取tmp=max(tmp1,ma-a[i][j]+p)。

最后发现每个点我们都可以同时看成经过和没被经过这样取,因为不会影响最后的答案。最后取ans=min(ans,tmp)。

四个部分的求最大子矩阵时一定要想清楚每一重for的含义。。。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define mst(head,x,n) memset(head+1,x,n*sizeof(head[0]))
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int maxn=150+5;
const int MAXN=1e7+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
//const ll mo=1e9+7;
int n,m,k;
int L[maxn],R[maxn],U[maxn],D[maxn];
int a[maxn][maxn],sum[maxn],c[maxn];
int ans,tmp,cnt;
int flag;
template <typename T>
inline void read(T &X){
    X=0;int w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    if(w) X=-X;
}
int main(){
    int T,cas=1;
    //read(T);
    //while(T--)
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        //read(n);read(m);read(k);
        rep(i,1,n){
            rep(j,1,m) scanf("%d",&a[i][j]);
            //read(a[i][j]);
        }
        rep(i,0,max(n,m)+1)
        L[i]=R[i]=U[i]=D[i]=-inf;
        rep(i,1,n){
            rep(j,1,m) sum[j]=0;
            rep(j,i,n){
                int tmp=0;
                rep(k,1,m){
                    sum[k]+=a[j][k];
                    tmp+=sum[k];
                    U[j]=max(U[j],tmp);
                    if(tmp<0) tmp=0;
                }
            }
            U[i]=max(U[i],U[i-1]);
        }
        dep(i,n,1){
            rep(j,1,m) sum[j]=0;
            dep(j,i,1){
                int tmp=0;
                rep(k,1,m){
                    sum[k]+=a[j][k];
                    tmp+=sum[k];
                    D[j]=max(D[j],tmp);
                    if(tmp<0) tmp=0;
                }
            }
            D[i]=max(D[i],D[i+1]);
        }
        rep(i,1,m){
            rep(j,1,n) sum[j]=0;
            rep(j,i,m){
                int tmp=0;
                rep(k,1,n){
                    sum[k]+=a[k][j];
                    tmp+=sum[k];
                    L[j]=max(L[j],tmp);
                    if(tmp<0) tmp=0;
                }
            }
            L[i]=max(L[i],L[i-1]);
        }
        dep(i,m,1){
            rep(j,1,n) sum[j]=0;
            dep(j,i,1){
                int tmp=0;
                rep(k,1,n){
                    sum[k]+=a[k][j];
                    tmp+=sum[k];
                    R[j]=max(R[j],tmp);
                    if(tmp<0) tmp=0;
                }
            }
            R[i]=max(R[i],R[i+1]);
        }
        int ans=U[n];
        rep(i,1,n){
            rep(j,1,m) {
                int tmp=-inf;
                tmp=max(U[i-1],D[i+1]);
                tmp=max(tmp,max(L[j-1],R[j+1]));
                tmp=max(tmp,U[n]-a[i][j]+k);
                ans=min(ans,tmp);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值