P3625 [APIO2009]采油区域(前缀和)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3625 [APIO2009]采油区域(前缀和)相关的知识,希望对你有一定的参考价值。
P3625 [APIO2009]采油区域(前缀和)
前缀和的好题。
考虑将矩形分成三部分有多少情况。
一共只有六种。
然后就是预处理4个角的最大值前缀和值,和从第i行到第j行的最大前缀和值,第i列到第j列的最大前缀和值。
一般矩形范围在 n , m ≤ 1 0 3 n,m\\le 10^3 n,m≤103的,显然就是 O ( n m ) O(nm) O(nm)的解法。
时间复杂度: O ( n m ) O(nm) O(nm)
// Problem: P3625 [APIO2009]采油区域
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3625
// Memory Limit: 125 MB
// Time Limit: 1500 ms
// Date: 2021-08-24 14:24:53
// --------by Herio--------
#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;
}
来归纳下,如果分成 2 2 2份,就是切一刀,显然只需预处理两个数组即可。
分成4份,原做法复杂度会爆炸,因为枚举的东西不止二维。
以上是关于P3625 [APIO2009]采油区域(前缀和)的主要内容,如果未能解决你的问题,请参考以下文章