UVa 10827 Maximum sum on a torus 解题报告(前缀和)

56 篇文章 0 订阅

Problem H
Maximum sum on a torus
Input:
Standard Input

Output: Standard Output

 

Agrid that wraps both horizontally and vertically is called a torus. Given atorus where each cell contains an integer, determine the sub-rectangle with thelargest sum. The sum of a sub-rectangle is the sum of all the elements in thatrectangle. The grid below shows a torus where the maximum sub-rectangle hasbeen shaded.

 

1

-1

0

0

-4

2

3

-2

-3

2

4

1

-1

5

0

3

-2

1

-3

2

-3

2

4

1

-4

Input

The first line in the input contains the number oftest cases (at most 18). Each case starts with an integer N(1≤N≤75) specifying the size of the torus (always square). Thenfollows N lines describing the torus, each line containing N integers between-100 and 100, inclusive.

 

Output

For each test case, output aline containing a single integer: the maximum sum of a sub-rectangle within thetorus.

 

Sample Input                                  Output for Sample Input

2
5
1 -1 0 0 -4
2 3 -2 -3 2
4 1 -1 5 0
3 -2 1 -3 2
-3 2 4 1 -4
3
1 2 3
4 5 6
7 8 9
15

45


Problem setter: Jimmy Mårdell

Special Thanks: Derek Kisman, Md.Kamruzzaman


    解题报告: 给定的矩阵是收尾相连的。可以先把给定的矩阵复制到右面,下面,以及右下角,再在新的矩阵中选择一个长宽不大于n的最大矩阵。

    求出新矩阵的前缀和,枚举左右边界,用优先队列保存已计算行的最小值,超过宽度n则删除。统计最大值即可。代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
using namespace std;

#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define mem(a) memset((a), 0, sizeof(a))
typedef long long LL;
typedef unsigned long long ULL;
void work();

int main()
{
#ifdef ACM
    freopen("in.txt", "r", stdin);
//    freopen("in.txt", "w", stdout);
#endif // ACM

    work();
}

/*****************************************/

struct Node
{
    int row, val;
    bool operator<(const Node & cmp) const
    {
        return val > cmp.val;
    }
} x;

int num[155][155];

void work()
{
    int T;
    scanf("%d", &T);
    ff(cas, T)
    {
        int n;
        scanf("%d", &n);

        fff(i, 1, n) fff(j, 1, n)
        {
            scanf("%d", &num[i][j]);
            num[i+n][j+n] = num[i+n][j] = num[i][j+n] = num[i][j];
        }

        int n2 = n * 2;
        fff(i, 1, n2) fff(j, 1, n2)
            num[i][j] += num[i-1][j] + num[i][j-1] - num[i-1][j-1];

        int ans = num[n][n];
        fff(j2, 1, n2) fff(j1, max(1, j2-n+1), j2)
        {
            priority_queue<Node> que;
            x.row = 0;
            x.val = 0;
            que.push(x);

            fff(i, 1, n2)
            {
                // 删去不符合条件的最小值
                while(que.top().row + n < i)
                    que.pop();

                int sum = num[i][j2] - num[i][j1-1];
                ans = max(ans, sum - que.top().val);

                // 更新最小值
                x.row = i;
                x.val = sum;
                que.push(x);
            }
        }

        printf("%d\n", ans);
    }
}

    速度一般般了,有更快的方法。不过这么写比较方便。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值