BZOJ-1177 [Apio2009]Oil

解题思路:

一种非常神奇的枚举策略...不过这种枚举策略...是需要DP来完成的

嘛...这种神奇的题目我独立肯定是做不来的...所以我是看着这篇博客写的...传送门

嘛...这篇博客好就好在...你必须要想通了你才知道这个代码是怎么回事...太可怕了%%%

首先,因为题目说了, 必须要是三个k*k的矩形,那么其实相对来说比较容易的想法就是一个个去枚举,但是肯定会超时。

那么考虑一个问题,就是这三个矩形的位置大概是怎么样的。

既然这三个矩形是互相不相交的,那么肯定就只有6种情况。


就是这样的6种情况...嘛用Windows自带的画图画的...有点丑...不要在意细节

这样...用a,b,c,d四个数组,先描述出左上,右上,左下,右下的前面的最大的k*k矩阵和

然后再分别描述这六幅图的情况,就可以求出最大值了。

代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;

const int maxn = 1505;

int sum[maxn][maxn];
int a[maxn][maxn], b[maxn][maxn], c[maxn][maxn], d[maxn][maxn];

int main() {
	int m, n, k, val;
	scanf("%d%d%d", &m, &n, &k);
	for (int i = 1; i <= m; ++i) {
		for (int j = 1; j <= n; ++j) {
			scanf("%d", &val);
			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + val;
		}
	}
	for (int i = m; i >= k; --i) {
		for(int j = n; j >= k; --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]));
	}
	//枚举六种情况,求出最大值
	int ans = 0;
	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 << 1); j <= n; ++j)
			ans = max(ans, a[m][j - k] + b[i][j] + d[i + k][j]);
	}
	for (int i = k; i <= m - k; ++i) {
		for (int j = k; j <= n - k; ++j)
			ans = max(ans, a[i][j] + b[m][j + k] + c[i + k][j]);
	}
	for (int i = (k << 1); i <= m; ++i) {
		for (int j = k; j <= n - k; ++j)
			ans = max(ans, a[i - k][n] + c[i][j] + d[i][j + k]);
	}
	for (int i = k; i <= m; ++i) {
		for (int j = (k << 1); j <= n - k; ++j)
			ans = max(ans, sum[i][j] + a[m][j - k] + b[m][j + k]);
	}
	for (int i = (k << 1); i <= m - k; ++i) {
		for (int j = k; j <= n; ++j)
			ans = max(ans, sum[i][j] + a[i - k][n] + c[i + k][n]);
	}
	printf("%d\n", ans);
	//system("pause");
	return 0;
}


posted @ 2016-09-04 14:38  _Wilbert  阅读(123)  评论(0编辑  收藏  举报