虽然题目说着分两种类型,其实就是相当于对于每一行,选择一个矩形去框
那么这样就统一了形式,而我们发现,每一行只跟上一行相关。
还有一个问题是交叉部分的去重,我们发现这有三种情况,因此对于三种情况分别讨论
但是枚举更新复杂度太高,因此想到优化,这种优化比较套路,用线段树求区间最大值就行
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=1e5+10; const int mod=1e9+7; const ll inf=1e12; int n,m,k; int a[55][20200]; ll sum[55][20200]; ll f[20200]; struct node{ int l,r; ll mx; }; struct Tree{ node tr[N<<2]; void build(int u,int l,int r){ if(l==r){ tr[u]={l,r,-inf}; } else{ tr[u]={l,r}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } } void pushup(int u){ tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx); } void modify(int u,int l,int r,ll x){ if(tr[u].l>=l&&tr[u].r<=r){ tr[u].mx=x; return ; } int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l,r,x); if(r>mid) modify(u<<1|1,l,r,x); pushup(u); } ll query(int u,int l,int r){ if(l>r) return -1e12; if(tr[u].l>=l&&tr[u].r<=r){ return tr[u].mx; } int mid=tr[u].l+tr[u].r>>1; ll ans=-1e12; if(l<=mid) ans=max(ans,query(u<<1,l,r)); if(r>mid) ans=max(ans,query(u<<1|1,l,r)); return ans; } }T[5]; int main(){ ios::sync_with_stdio(false); cin>>n>>m>>k; int i,j; for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ cin>>a[i][j]; sum[i][j]=sum[i][j-1]+a[i][j]; } } T[1].build(1,1,m+10); T[2].build(1,1,m+10); T[3].build(1,1,m+10); for(i=1;i<=n;i++){ for(j=1;j+k-1<=m;j++){ f[j]=max(T[3].query(1,1,j-k),T[3].query(1,j+k,m)); f[j]=max(f[j],T[1].query(1,j-k+1,j)+sum[i][j-1]); f[j]=max(f[j],T[2].query(1,j+1,j+k)-sum[i][j+k-1]); f[j]=max(f[j],0ll); } for(j=1;j+k-1<=m;j++){ f[j]+=(sum[i][j+k-1]-sum[i][j-1]); f[j]+=(sum[i+1][j+k-1]-sum[i+1][j-1]); T[1].modify(1,j,j,f[j]-sum[i+1][j+k-1]); T[2].modify(1,j,j,f[j]+sum[i+1][j-1]); T[3].modify(1,j,j,f[j]); } } cout<<T[3].query(1,1,m)<<endl; return 0; }View Code