【题解】utpc2021_g Matrix Compressor

utpc2021_g Matrix Compressor

题意

给定 \(n\)\(m\) 列的矩阵 \(a\)

你需要进行如下操作直到矩阵 \(a\) 大小变为 \(1\times 1\)

  • 合并相邻的两行,贡献是参与合并的行内所有数字之和。

  • 合并相邻的两列,贡献是参与合并的列内所有数字之和。

请求出能得到的最大贡献。

\(n,m\le 3\times 10^3\)

题解

知识点:动态规划。

手玩几组数据,容易发现行和列的合并是独立的,列的合并,不会影响某一行的数的总和,反过来同理。

所以可以预处理出每一行和列的所有数的总和。

那么就变成了经典问题石子合并,不过这里求的是最大贡献。

行和列是一样的,这里只讨论行,设第 \(1\sim i\) 行所有数的为 \(s_i\)

\(dp_{l,r}\) 为合并第 \(l\sim r\) 行后产生的最大贡献。

则有转移:

\[dp_{l,r}=\max(dp_{l+1,r},dp_{l,r-1}) + h_r-h_{l-1} \]

为什么不用枚举分割点,因为求的是最大的贡献,一个数一个数的合并会使合并次数更多,而上式的本质就是给每个数决定它贡献的次数,同时假设合并 \([l,k],[k+1,r]\),且前者区间长度小于后者长度,则合并 \([l,k-1],[k,r]\) 更优,因为区间长度更长合并次数更多,贡献次数更多,那么最终转移的区间只能是两个极端点,也就是 \([l+1,r],[l,l]\)\([l,r-1],[r,r]\)

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

#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()

#define N 3005
#define int long long

int n,m,a[N][N],hs[N],ls[N],f[N][N],g[N][N];

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);

    cin>>n>>m;

    rep(i,1,n){
        rep(j,1,m){
            char c;
            cin>>c;

            a[i][j]=c-'0';

            hs[i]+=a[i][j];
            ls[j]+=a[i][j];
        }
    }

    rep(i,1,n){
        rep(j,1,n){
            f[i][j]=-1e18;
        }
    }
    rep(i,1,m){
        rep(j,1,m){
            g[i][j]=-1e18;
        }
    }

    rep(i,1,n){
        hs[i]+=hs[i-1];
        f[i][i]=0;
    }
    rep(i,1,m){
        ls[i]+=ls[i-1];
        g[i][i]=0;
    }

    rep(len,2,n){
        rep(l,1,n){
            int r=l+len-1;

            if(r>n){
                break;
            }

            f[l][r]=max(f[l+1][r],f[l][r-1])+hs[r]-hs[l-1];
        }
    }

    rep(len,2,m){
        rep(l,1,m){
            int r=l+len-1;

            if(r>m){
                break;
            }

            g[l][r]=max(g[l+1][r],g[l][r-1])+ls[r]-ls[l-1];
        }
    }

    cout<<f[1][n]+g[1][m];

    return 0;
}
posted @ 2025-07-22 16:35  Lucyna_Kushinada  阅读(14)  评论(0)    收藏  举报