LG3625 [APIO2009]采油区域(前缀和+DP)
LG3625 [APIO2009]采油区域
前言
重复的思维,重复的代码,重复地调试。
我已AC,感觉良好
解法1
没啥技巧,看一眼就知道怎么做了。
分为 \(6\) 个情况,哪 \(6\) 种可以看别的大佬的 blog。这篇题解只要讲一下别的大佬没有仔细讲的预处理部分。
我们要处理出来的是 \(7\) 个量。见下:
量: | \(sum_{i,j}\) | \(lu_{i,j}\) | \(ld_{i,j}\) | \(ru_{i,j}\) | \(rd_{i,j}\) | \(ver_{i,j}\) | \(hor_{i,j}\) |
---|---|---|---|---|---|---|---|
含义: | 左上角矩阵中数字的和 | 左上角最大 \(k*k\) 矩阵数字和 | 左下角最大 \(k*k\) 矩阵数字和 | 右上角最大 \(k*k\) 矩阵数字和 | 右下角最大 \(k*k\) 矩阵数字和 | \(i\) 到 \(j\) 列最大 \(k*k\) 矩阵数字和 | \(i\) 到 \(j\) 行最大 \(k*k\) 矩阵数字和 |
我们要把每个量处理出来。\(sum\) 就是二维前缀和,用于计算后面 \(6\) 个量,\(lu,ld,ru,rd\) 四个量用 DP 求解。\(ver,hor\) 用区间 DP 求解。
最后 \(6\) 种情况讨论一下即可。
解法2
两位神 @cookiebus @code_hunter 貌似有另一种解法,我没太看懂他们的代码。他们又没写题解,感兴趣的小伙伴可以去问一下。
代码
这代码,你不看也罢。反正你看了根没看差不多
祝你好运!
注意不要开 long long,会MLE!
//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
using namespace std;
int read() {
char ch=getchar();
int f=1,x=0;
while(ch<'0'||ch>'9') {
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return f*x;
}
const int MAXN=15e2+10;
int n,m,k,ans;
int sum[MAXN][MAXN],a[MAXN][MAXN];
int lu[MAXN][MAXN],ld[MAXN][MAXN],rd[MAXN][MAXN],ru[MAXN][MAXN],hor[MAXN][MAXN],ver[MAXN][MAXN];
int gets(int x,int y,int a,int b) {
return sum[a][b]+sum[x-1][y-1]-sum[x-1][b]-sum[a][y-1];
//用 sum 计算一个子矩阵中的数字和
}
signed main() {
cin>>n>>m>>k;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
a[i][j]=read();
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
}
}
for(int i=k;i<=n;i++) {
for(int j=k;j<=m;j++) {
lu[i][j]=max(max(lu[i][j-1],lu[i-1][j]),gets(i-k+1,j-k+1,i,j));
}
}
for(int i=k;i<=n;i++) {
for(int j=m-k+1;j;j--) {
ru[i][j]=max(max(ru[i][j+1],ru[i-1][j]),gets(i-k+1,j,i,j+k-1));
}
}
for(int i=n-k+1;i;i--) {
for(int j=1;j<=m;j++) {
ld[i][j]=max(max(ld[i][j-1],ld[i+1][j]),gets(i,j-k+1,i+k-1,j));
}
}
for(int i=n-k+1;i;i--) {
for(int j=m-k+1;j;j--) {
rd[i][j]=max(max(rd[i][j+1],rd[i+1][j]),gets(i,j,i+k-1,j+k-1));
}
}
for(int i=1;i<=n-k+1;i++) {
for(int j=1;j<=m-k+1;j++) {
hor[i][i+k-1]=max(hor[i][i+k-1],gets(i,j,i+k-1,j+k-1));
}
}
for(int len=k+1;len<=n;len++) {
for(int i=1,j=i+len-1;j<=n;j++,i++) {
hor[i][j]=max(hor[i+1][j],hor[i][j-1]);
}
}
for(int i=1;i<=m-k+1;i++) {
for(int j=1;j<=n-k+1;j++) {
ver[i][i+k-1]=max(ver[i][i+k-1],gets(j,i,j+k-1,i+k-1));
}
}
for(int len=k+1;len<=m;len++) {
for(int i=1,j=i+len-1;j<=m;j++,i++) {
ver[i][j]=max(ver[i+1][j],ver[i][j-1]);
}
}
//预处理
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
ans=max(ans,hor[i+1][n]+lu[i][j]+ru[i][j+1]);
ans=max(ans,hor[1][i]+ld[i+1][j]+rd[i+1][j+1]);
ans=max(ans,ver[j+1][m]+lu[i][j]+ld[i+1][j]);
ans=max(ans,ver[1][j]+ru[i][j+1]+rd[i+1][j+1]);
}
}
for(int i=1;i<=n;i++) {
for(int j=i+1;j<=n;j++) {
ans=max(ans,hor[1][i]+hor[i+1][j]+hor[j+1][n]);
}
}
for(int i=1;i<=m;i++) {
for(int j=1;j<=m;j++) {
ans=max(ans,ver[1][i]+ver[i+1][j]+ver[j+1][m]);
}
}
//计算答案
cout<<ans<<endl;
return 0;
}