HDU 5749 Colmerauer(单调栈或单调队列求解固定区间最大或最小值)

Colmerauer

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 276    Accepted Submission(s): 118


Problem Description
Peter has an  n×m  matrix  M . Let  S(a,b)  be the sum of the weight all  a×b  submatrices of  M . The weight of matrix is the sum of the value of all the saddle points in the matrix. A saddle point of a matrix is an element which is both the only largest element in its column and the only smallest element in its row. Help Peter find out all the value of  S(a,b) .

Note: the definition of saddle point in this problem may be different with the definition you knew before.
 

Input
There are multiple test cases. The first line of input contains an integer  T , indicating the number of test cases. For each test case:

The first contains two integers  n  and  m   (1n,m1000)  -- the dimensions of the matrix.

The next  n  lines each contain  m  non-negative integers separated by spaces describing rows of matrix  M  (each element of  M  is no greater than  106 ).
 

Output
For each test case, output an integer  W=(a=1nb=1mabS(a,b)) mod 232 .
 

Sample Input
  
3 2 2 1 1 1 1 3 3 1 2 3 4 5 6 7 8 9 3 3 1 2 1 2 3 1 4 5 2
 

Sample Output
  
4 600 215
 

Source
 

对于矩阵种一个元素M(x,y)M(x,y)考虑他可以成为那些子矩阵的鞍点, 用单调队列之类的东西处理出a,b,c,da,b,c,d, 分别表示在第xx行中, 这个元素在第y-aya列到y+by+b列中都是唯一最小值; 第yy列中, 这个元素在第x-cxcx+dx+d行中都是唯一最大值.

对于公式, 只需要推导下这个元素对整体式子的贡献就好了.

#include <map>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define uint unsigned int
using namespace std;
const int MAXN = 1e3 + 5;
int L[MAXN][MAXN], R[MAXN][MAXN], U[MAXN][MAXN], D[MAXN][MAXN];
int n, m, O[MAXN][MAXN], T;
//L[i][j]代表满足条件的左边端点
int sta[MAXN];
uint cal(int l, int x, int r) {
	uint a = r - x + 1;
	uint b = x - l + 1;
	return a * (a + 1) / 2 * b +  b * (b - 1) / 2 * a;
}
int main() {
	while(~scanf("%d", &T)) {
		while(T --) {
			scanf("%d%d", &n, &m);
			for(int i = 0; i < n; i ++) {
				for(int j = 0; j < m; j ++) {
					scanf("%d", &O[i][j]);
				}
			}
			int top = 0;
			for(int i = 0; i < n; i ++) {
				top = 0;
				for(int j = 0; j < m; j ++) {
					while(top && O[i][sta[top - 1]] > O[i][j]) top --;
					if(top == 0) L[i][j] = 0;
					else L[i][j] = sta[top - 1] + 1;
					sta[top ++] = j;
				}
				top = 0;
				for(int j = m - 1; j >= 0; j --) {
					while(top && O[i][sta[top - 1]] > O[i][j]) top --;
					if(top == 0) R[i][j] = m - 1;
					else R[i][j] = sta[top - 1] - 1;
					sta[top ++] = j;
				}
			}
			for(int i = 0; i < m; i ++) {
				top = 0;
				for(int j = 0; j < n; j ++) {
					while(top && O[sta[top - 1]][i] < O[j][i]) top --;
					if(top == 0) U[j][i] = 0;
					else U[j][i] = sta[top - 1] + 1;
					sta[top ++] = j;
				}
				top = 0;
				for(int j = n - 1; j >= 0; j --) {
					while(top && O[sta[top - 1]][i] < O[j][i]) top --;
					if(top == 0) D[j][i] = n - 1;
					else D[j][i] = sta[top - 1] - 1;
					sta[top ++] = j;
				}
			}

			uint ret = 0;
			for(int i = 0; i < n; i ++) {
				for(int j = 0; j < m; j ++) {
					ret += (uint)O[i][j] * cal(L[i][j], j, R[i][j]) * cal(U[i][j], i, D[i][j]);
				}
			}
			printf("%u\n", ret);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值