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);
}
}
速度一般般了,有更快的方法。不过这么写比较方便。