省选专练APIO2009Oil采油区域


神仙题

难点在于代码实现

这狗日的题。。。

首先暴力是这样的

枚举三个坐标

这是n^6做法,没什么卵用

但是我们发现把一张图分割成3块那么可以做

但是问题是这是情况多多的

所以成了码农题

#include<bits/stdc++.h>
using namespace std;
const int N=1801;
int sum[N][N]={};
int a[N][N]={};//左上 
int b[N][N]={};//右上 
int c[N][N]={};//左下 
int d[N][N]={};//右下
int ans=-1; 
int m,n,k;
int main(){
	scanf("%d%d%d",&m,&n,&k);
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			int x;
			scanf("%d",&x);
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+x;
		}
	}
	for(int i=m;i>=k;i--){
		for(int j=n;j>=k;j--){
			sum[i][j]=sum[i][j]-sum[i-k][j]-sum[i][j-k]+sum[i-k][j-k];		
		}
	}
	//四个角
	for(int i=k;i<=m;i++){
		for(int j=k;j<=n;j++){
			a[i][j]=max(sum[i][j],max(a[i-1][j],a[i][j-1]));
		}
	} //左上角
	for(int i=k;i<=m;i++){
		for(int j=n;j>=k;j--){
			b[i][j]=max(sum[i][j],max(b[i-1][j],b[i][j+1]));
		}
	}//右上角 
	for(int i=m;i>=k;i--){
		for(int j=k;j<=n;j++){
			c[i][j]=max(sum[i][j],max(c[i+1][j],c[i][j-1]));
		}
	}//左下角 
	for(int i=m;i>=k;i--){
		for(int j=n;j>=k;j--){
			d[i][j]=max(sum[i][j],max(d[i+1][j],d[i][j+1]));
		}
	}
	//第一维枚举横线
	//第二维枚举竖线 
	for(int i=k;i<=m-k;i++){
		for(int j=k;j<=n-k;j++){
			ans=max(ans,a[i][j]+b[i][j+k]+c[i+k][n]);
		}
	}
	for(int i=k;i<=m-k;i++){
		for(int j=k+k;j<=n;j++){
			ans=max(ans,b[i][j]+d[i+k][j]+a[n][j-k]);
		}
	}
	for(int i=k+k;i<=m;i++){
		for(int j=k;j<=n-k;j++){
			ans=max(ans,c[i][j]+d[i][j+k]+a[i-k][n]);
		}
	}
	for(int i=k;i<=n-k;i++){
		for(int j=k;j<=m-k;j++){
			ans=max(ans,a[i][j]+c[i+k][j]+b[m][j+k]);
		}
	}
	//两条平行线
	for(int i=k;i<=n;i++){
		for(int j=k+k;j<=m-k;j++){
			ans=max(ans,sum[i][j]+a[i][j-k]+b[i][j+k]);
		}
	} 
	for(int i=k+k;i<=n-k;i++){
		for(int j=k;j<=m;j++){
			ans=max(ans,sum[i][j]+a[i-k][n]+c[i+k][n]);
		}
	} 
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/81037364