G - One More Grid Task Editorial by llichenyu

Without the Limitation of Ai,j

In this solution, We don’t need the limitation \(a_{i,j} \le 300\).

First, we enumerate the left boundary and the right boundary of the rectangle. We call them \(l\) and \(r\). It costs \(O(M^2)\) time.

Now consider the following values:

  • \(C_i\) = (the minimum value of line \(i\) in range \([l,r]\))

  • \(D_i\) = (the sum of values of line \(i\) in range \([l,r]\))

They can be found in a total of \(O(N)\) time.

And now the problem has been turned into a new problem:

You are given two positive interger sequences \(C=(C_1,C_2,\dots,C_N)\) and \(D=(D_1,D_2,\dots,D_N)\) of length \(N\). Find the maximum possible value of \((\min_{i=l'}^{r'} C_i) +(\sum_{i=l'}^{r'}D_i)\) for all of ranges \([l',r']\) between \(1\) and \(N\).

It’s a classic problem. For each \(i\) between \(1\) and \(N\), we find the maximum range \([L_i,R_i]\) that satisfies \(L_i \le i \le R_i\) and \(\min_{j=L_i}^{R_i} C_j=C_i\). The answer to the problem is \(\max_{i=1}^{N}(C_i \times \sum_{j=L_i}^{R_i} D_j)\).

We could find the ranges with the help of a monotonic stack, and the total complexity is \(O(N)\).

Hence, the problem can be solved in a total of \(O(NM^2)\) time without the limitation \(a_{i,j} \le 300\).

  • Sample Code (C++)
//A tree without skin will surely die.
//A man without face is invincible.
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define sqr(x) ((x)*(x))
#define all(x) (x).begin(),(x).end()
#define Tim ((double)clock()/CLOCKS_PER_SEC)
#define mid ((l+r)>>1)
#define lowbit(x) (x&-x)
int const N=3e2+10;
int a[N][N],c[N],d[N],l[N],r[N],s[N];
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int n,m;cin>>n>>m;
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j) cin>>a[i][j];
    int ans=0;
    for (int i=1;i<=m;++i){
        for (int k=1;k<=n;++k) d[k]=0,c[k]=1e9;
        for (int j=i;j<=m;++j){
            for (int k=1;k<=n;++k) d[k]+=a[k][j],c[k]=min(c[k],a[k][j]);
            for (int k=1;k<=n;++k) s[k]=s[k-1]+d[k];
            stack<int>ss;
            for (int k=1;k<=n;++k) l[k]=0,r[k]=n+1;
            for (int k=1;k<=n;++k){
                while (ss.size() && c[k]<c[ss.top()]) r[ss.top()]=k,ss.pop();
                ss.push(k);
            }
            while (ss.size()) ss.pop();
            for (int k=n;k>=1;--k){
                while (ss.size() && c[k]<c[ss.top()]) l[ss.top()]=k,ss.pop();
                ss.push(k);
            }
            for (int i=1;i<=n;++i) ++l[i],--r[i],ans=max(ans,c[i]*(s[r[i]]-s[l[i]-1]));
        }
    }
    cout<<ans<<'\n';
    return 0;
}

posted:
last update: