codeforces 173C Spiral Maximum (递推)

39 篇文章 0 订阅

Spiral Maximum

Time Limit:3000MS    Memory Limit:262144KB    64bit IO Format:%I64d & %I64u

Description

Let's consider a k × k square, divided into unit squares. Please note that k ≥ 3 and is odd. We'll paint squares starting from the upper left square in the following order: first we move to the right, then down, then to the left, then up, then to the right again and so on. We finish moving in some direction in one of two cases: either we've reached the square's border or the square following after the next square is already painted. We finish painting at the moment when we cannot move in any direction and paint a square. The figure that consists of the painted squares is a spiral.

The figure shows examples of spirals for k = 3, 5, 7, 9.

You have an n × m table, each of its cells contains a number. Let's consider all possible spirals, formed by the table cells. It means that we consider all spirals of any size that don't go beyond the borders of the table. Let's find the sum of the numbers of the cells that form the spiral. You have to find the maximum of those values among all spirals.

Input

The first line contains two integers n and m (3 ≤ n, m ≤ 500) — the sizes of the table.

Each of the next n lines contains m space-separated integers: the j-th number in the i-th line aij ( - 1000 ≤ aij ≤ 1000) is the number recorded in the j-th cell of the i-th row of the table.

Output

Print a single number — the maximum sum of numbers among all spirals.

Sample Input

Input
6 5
0 0 0 0 0
1 1 1 1 1
0 0 0 0 1
1 1 1 0 1
1 0 0 0 1
1 1 1 1 1
Output
17
Input
3 3
1 1 1
1 0 0
1 1 1
Output
6
Input
6 6
-3 2 0 1 5 -1
4 -1 2 -3 0 1
-5 1 2 4 1 -2
0 -2 1 3 -1 2
3 1 4 -3 -2 0
-1 2 -1 3 1 2
Output
13

Hint

In the first sample the spiral with maximum sum will cover all 1's of the table.

In the second sample the spiral may cover only six 1's.


题意:

在给出的n*n的矩阵中找到一个k*k的最大子矩阵(k>=3 && k为奇数)。子矩阵的值为从该矩阵左上角开始的蛇形(优先方向 右,下,左,上)上的数值之和。


思路:

题很好 和最大矩阵和相似,仔细分析下就可以发现这个求一个(r, c)开始的k*k子矩阵的值可以由对应的(r+2, c+2) 的 (k-4)*(k-4) 的子矩阵的值通过O(1)得到。所以可以直接递推


问题:

矩阵必须选择一个,也就是说ans初始值不能为0, 应该为-INF



#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>

using namespace std;

//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif

#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define S64I1(a) scanf(iform1, &(a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<(n); (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)

const int INF = 0x3f3f3f3f;
const double eps = 10e-9;
const double PI = (4.0*atan(1.0));

const int maxn = 500 + 20;
int n, m;
int A[maxn][maxn];
int rowSum[maxn][maxn], columSum[maxn][maxn];

int getQ(int r, int c, int k) {
    if(k == 1) return A[r][c];
    if(k == 2) return A[r][c] + A[r][c+1] + A[r+1][c+1];
    int t = rowSum[r][c+k-1] - rowSum[r][c-1];
    t += rowSum[r+k-1][c+k-1] - rowSum[r+k-1][c-1];
    t += columSum[r+k-1][c+k-1] - columSum[r-1][c+k-1];
    t += columSum[r+k-1][c] - columSum[r+1][c];
    t = t - A[r][c+k-1] - A[r+k-1][c] - A[r+k-1][c+k-1];
    return t;
}

bool isok(int r, int c, int k) {
    return r > 0 && r+k-1 <= n && c > 0 && c+k-1 <= m;
}

int main() {

    while(scanf("%d%d", &n, &m) != EOF) {
        FOR(i, 0, n) rowSum[i][0] = 0, columSum[0][i] = 0;
        REP1(i, n) REP1(j, m) {
            scanf("%d", &A[i][j]);
            rowSum[i][j] = A[i][j] + rowSum[i][j-1];
            columSum[i][j] = A[i][j] + columSum[i-1][j];
        }
        int ans = -INF;
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                int r = i;
                int c = j;
                int k = 1;
                int son = 0;
                while(isok(r, c, k)) {
                    int sum = getQ(r, c, k) + son;
                    if(k >= 3 && k%2==1 && sum > ans) {
                        ans = sum;
                    }
                    son = sum + A[r][c-1];
                    r -= 2;
                    c -= 2;
                    k += 4;
                } // 这里比较累赘 
                r = i;
                c = j;
                k = 3;
                son = 0;
                while(isok(r, c, k)) {
                    int sum = getQ(r, c, k) + son;
                    if(k >= 3 && k%2==1 && sum > ans) {
                        ans = sum;
                    }
                    son = sum + A[r][c-1];
                    r -= 2;
                    c -= 2;
                    k += 4;
                }
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值