zoukankan      html  css  js  c++  java
  • 洛谷 P3625 [APIO2009]采油区域

    Description

    原题链接

    Solution

    很巧妙的一种思想:分类讨论

    分为 6 种情况,如下图:

    可以发现,每一张图都被分为了 3 块,我们就可以分别在这三个部分中各选择一个 (k * k) 的矩形,取最大值。

    具体实现:

    首先要进行预处理,设一个点为 ((x, y))

    我们要预处理出以这个点为端点向左上右上左下右下,四个方向分别的最大子矩阵。

    然后我们枚举上图中每个矩形中的那两条线,再取最大值即可。

    具体看代码吧。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define ri register int
    
    using namespace std;
    
    const int N = 1510;
    int n, m, k, ans;
    int sum[N][N], s[N][N], a[N][N], b[N][N], c[N][N], d[N][N];
    //sum:前缀和  s: k * k区间和(详见下面) a,b,c,d: 四个方向,下面有图
    
    inline int read(){
    	int x = 0;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    	return x;
    }
    
    /*
    a  |  b 
    ———+————
    c  |  d
    */
    
    inline void init(){
    	for(ri i = 1; i <= n; ++i)
    		for(ri j = 1; j <= m; ++j)
    			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + read();//二维前缀和
    	for(ri i = k; i <= n; ++i)
    		for(ri j = k; j <= m; ++j)
    			s[i][j] = sum[i][j] - sum[i][j - k] - sum[i - k][j] + sum[i - k][j - k];//k * k区间和
    //4 个方向预处理最大子矩阵
    	for(ri i = k; i <= n; ++i)
    		for(ri j = k; j <= m; ++j)
    			a[i][j] = max(s[i][j], max(a[i][j - 1], a[i - 1][j]));
    	for(ri i = k; i <= n; ++i)
    		for(ri j = m - k + 1; j >= 1; j--)
    			b[i][j] = max(s[i][j + k - 1], max(b[i - 1][j], b[i][j + 1]));
    	for(ri i = n - k + 1; i >= 1; i--)
    		for(ri j = k; j <= m; ++j)
    			c[i][j] = max(s[i + k - 1][j], max(c[i + 1][j], c[i][j - 1]));
    	for(ri i = n - k + 1; i >= 1; i--)
    		for(ri j = m - k + 1; j >= 1; j--)
    			d[i][j] = max(s[i + k - 1][j + k - 1], max(d[i + 1][j], d[i][j + 1]));
    }
    
    /*
    a  |  b 
    ———+————
    c  |  d
    */
    
    inline void solve(){
    	//两条竖线,两条横线的情况
    	for(ri i = k; i <= n; ++i)
    		for(ri j = k; j <= m; ++j){
    			ans = max(ans, a[i - k][m] + s[i][j] + c[i + 1][m]);//两条横线
    			ans = max(ans, a[n][j - k] + s[i][j] + b[n][j + 1]);//两条竖线
    		}
    	//剩下 4 种情况
    	for(ri i = 1; i <= n; ++i)
    		for(ri j = 1; j <= m; ++j){
    			ans = max(ans, a[i][j] + b[i][j + 1] + c[i + 1][m]);
    			ans = max(ans, a[i][m] + c[i][j] + d[i + 1][j + 1]);
    			ans = max(ans, a[i][j] + b[n][j + 1] + c[i + 1][j]);
    			ans = max(ans, a[n][j] + b[i][j + 1] + d[i + 1][j + 1]);
    		}
    }
    
    signed main(){
    	n = read(), m = read(), k = read();
    	init();
    	solve();
    	printf("%lld
    ", ans);
    	return 0;
    }
    

    End

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15354957.html

  • 相关阅读:
    《秋日》 -- 程颢
    《安乐吟》 -- 邵雍
    《大学》笔记
    《跨越鸿沟》笔记
    庄子《齐物论》—— 方生方死、因是因非是对立统一规律的起源
    《饮酒(其五)》陶渊明
    《亲密关系》笔记
    《人生的智慧》笔记
    《历史的教训》笔记
    《格鲁夫给经理人的第一课》笔记
  • 原文地址:https://www.cnblogs.com/xixike/p/15354957.html
Copyright © 2011-2022 走看看