题解 P3625 【[APIO2009]采油区域】
首先声明一下,排的数量此题解和我的代码中记作
首先,一定可以划出一条直线(而且一定划在整数位置,竖线的话横坐标为整数,横线的话纵坐标为整数),把整个这个东西很好证明,于是作为读者习题。
显然的,两个矩形的情况当然也可以完整分开。于是三个矩形的分布只能如图所示,其中每个正方形显然都是所在区域贡献最大的正方形。
只有两条分割线,可以
那么,这就是一个在矩形区域里选择一个贡献最大的ne[][],se[][],sw[][],nw[][],即以某个方块为顶点的右上↗矩形,右下↘矩形,左下↙矩形,左上↖矩形中贡献最大的hen[][],shu[][]表示从第
二维的区域和,瞬间想到二维前缀和,构建数组k[][]。
如下图是一个以红方格为顶点的右上正方形。
还是考虑二维前缀和思想,我们以nw[][]数组为例。
如图,
于是容易写出:
大家会发现既在淡蓝矩形又在深蓝矩形的正方形统计了两遍,然而反正是取最大值所以完全没有问题。
如此,前四个数组很好搞出,接下来是剩下的两个。我们以hen[][]为例。
对于hen[i][i+K-1],非常显然它就是
对于其他的情况hen[i][j],直接区间DP:
然后直接开始统计即可~下面是代码。
虽然看着有点恶心,但思路非常清晰。
调不出来的话再回顾一下上面的思路吧。
#include<bits/stdc++.h>
using namespace std;
int N,M,K; //个人习惯,N才表示行
int s[1505][1505],k[1505][1505];
int ne[1505][1505],se[1505][1505],sw[1505][1505],nw[1505][1505];
int hen[1505][1505],shu[1505][1505];
int ANS;
int main(){
cin>>N>>M>>K;
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++){
int a;cin>>a; //懒得设a数组了
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;
}
for(int i=K;i<=N;i++) //左上K*K正方形
for(int j=K;j<=M;j++){
k[i][j]=s[i][j]-s[i-K][j]-s[i][j-K]+s[i-K][j-K];
}
for(int i=K;i<=N;i++) //nw,sw,se,ne
for(int j=K;j<=M;j++)
nw[i][j]=max(nw[i-1][j],max(nw[i][j-1],k[i][j]));
for(int i=N-K+1;i>=1;i--)
for(int j=K;j<=M;j++)
sw[i][j]=max(sw[i+1][j],max(sw[i][j-1],k[i+K-1][j]));
for(int i=N-K+1;i>=1;i--)
for(int j=M-K+1;j>=1;j--)
se[i][j]=max(se[i+1][j],max(se[i][j+1],k[i+K-1][j+K-1]));
for(int i=K;i<=N;i++)
for(int j=M-K+1;j>=1;j--)
ne[i][j]=max(ne[i-1][j],max(ne[i][j+1],k[i][j+K-1]));
for(int i=1;i<=N-K+1;i++) //横排
for(int j=K;j<=M;j++)
hen[i][i+K-1]=max(hen[i][i+K-1],k[i+K-1][j]);
for(int len=K+1;len<=N;len++)
for(int i=1;i<=N-len+1;i++)
hen[i][i+len-1]=max(hen[i+1][i+len-1],hen[i][i+len-2]);
for(int j=1;j<=M-K+1;j++) //竖列
for(int i=K;i<=N;i++)
shu[j][j+K-1]=max(shu[j][j+K-1],k[i][j+K-1]);
for(int len=K+1;len<=M;len++)
for(int j=1;j<=M-len+1;j++)
shu[j][j+len-1]=max(shu[j+1][j+len-1],shu[j][j+len-2]);
for(int x1=K;x1<=N-K;x1++) //统计,注意区域间千万不能有相交!
for(int x2=K;x2<=M-K;x2++){
ANS=max(ANS,shu[1][x2]+ne[x1][x2+1]+se[x1+1][x2+1]); //图1
ANS=max(ANS,shu[x2+1][M]+nw[x1][x2]+sw[x1+1][x2]); //图3
ANS=max(ANS,hen[x1+1][M]+nw[x1][x2]+ne[x1][x2+1]); //图4
ANS=max(ANS,hen[1][x1]+sw[x1+1][x2]+se[x1][x2+1]); //图6
}
for(int x1=K;x1<=N-2*K;x1++) //图2
for(int x2=x1+K;x2<=N-K;x2++)
ANS=max(ANS,hen[1][x1]+hen[x1+1][x2]+hen[x2+1][N]);
for(int x1=K;x1<=M-2*K;x1++) //图4
for(int x2=x1+K;x2<=M-K;x2++)
ANS=max(ANS,shu[1][x1]+shu[x1+1][x2]+shu[x2+1][N]);
cout<<ANS;
}