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;
}
posted @ 2021-05-02 17:29  huayucaiji  阅读(69)  评论(0编辑  收藏  举报