cf Croc Champ 2012 - Round 1 C. Spiral Maximum

C. Spiral Maximum
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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 test(s)
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
Note

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*m的地图中找一个k*k(k为≥3的奇数)的区域,从左上角区域出发,按右、下、左、上的顺序走,当下一个点为边界或者下下个点已经走过就改变方向(如图黑色部分),找一条这样的路径使得所经过的区域路径最大。


思路:

枚举起点,枚举k,O(1)的时间算所经过的路径之和,观察规律可知路径是一圈一圈的,

dp[k][i][j]表示起点为i,j,边长为k时的路径之和,那么dp[k][i][j]=dp[k-4][i+2][j+2]+最外圈的和减去一个点加上一个点。

可以不用存下来,算出i,j后,将起点上移,充分发挥它的作用就行。

比赛时我存下来按照边长的顺序递推出来的,将奇数压缩,开着三维数组过去的,有点衰~


代码:(比赛时代码,有点挫)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define maxn 502
#define MAXN 100005
#define mod 100000000
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;

int n,m,ans;
int a[maxn][maxn],sum[maxn][maxn];
int dp[maxn][maxn][206];

int cal1(int x,int y,int k)
{
    return sum[x+k-1][y+k-1]-sum[x-1][y+k-1]-sum[x+k-1][y-1]+sum[x-1][y-1];
}
int cal(int x,int y,int k)
{
    int t;
    t=cal1(x,y,k)-cal1(x+1,y+1,k-2);
    return t;
}
int main()
{
    int i,j,t,k,p,sx,sy,ex,ey;
    while(~scanf("%d%d",&n,&m))
    {
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=m; j++)
            {
                scanf("%d",&a[i][j]);
                sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
            }
        }
        ans=-INF;
        int best,edge;
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=m; j++)
            {
                dp[i][j][0]=a[i][j];
                k=3;
                if(i+k-1>n||j+k-1>m) continue ;
                sx=i; sy=j;
                ex=i+k/2; ey=j+k/2;
                edge=k;
                best=0;
                while(1)
                {
                    if(edge>3) best+=cal(sx,sy,edge)-a[sx+1][sy]+a[sx+2][sy+1];
                    else if(edge==3) best+=cal(sx,sy,edge)-a[sx+1][sy];
                    else best+=a[sx][sy];
                    sx+=2;
                    sy+=2;
                    if(sx>ex&&sy>ey) break ;
                    edge-=4;
                }
                dp[i][j][1]=best;
                ans=max(ans,best);
            }
        }
        int mi=min(n,m);
        for(k=5; k<=mi; k+=2)
        {
            for(i=1; i<=n; i++)
            {
                for(j=1; j<=m; j++)
                {
                    if(i+k-1>n||j+k-1>m) continue ;
                    dp[i][j][k/2]=cal(i,j,k)-a[i+1][j]+a[i+2][j+1]+dp[i+2][j+2][(k-4)/2];
                    ans=max(ans,dp[i][j][k/2]);
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值