标签:
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
4 600 215
Peter有一个n×m的矩阵M.定义S(a,b)为M的所有大小为a×b的子矩阵的权值和.一个矩阵的权值是这个矩阵所有鞍点的值的和.在矩阵中,一个数在所在行中是唯一的最小值,在所在列中是唯一的最大值,则被称为鞍点.帮助Peter找出所有S(a,b)的值.
输出:
已知一个点的Up,Down,Left,Right,即上下左右的扩展范围,然后计算鞍点对答案的贡献。
把所有可能的矩形的长算出来,得到和,宽也是一样,然后按照乘法原理乘起来就好。
详细题解:BestCoder Round #84 (点击)Orz。。。
AC代码:
//#include<bits/stdc++.h> #include<iostream> #include<stdio.h> #include<cstring> #include<string.h> #include<algorithm> #define N 1010 using namespace std; int n,m; int a[N][N]; int stk[N],top; int L[N][N],R[N][N],U[N][N],D[N][N]; int readint() { char c; while((c=getchar())&&!(c>='0' && c<='9')); int ret= c- 48; while((c=getchar())&&( c>='0' && c<='9')) ret = ret * 10 + c-48; return ret; } unsigned int calc(int l,int x,int r) { unsigned int d1=r-x+1; unsigned int d2=x-l+1; unsigned int ret=d1 * (d1+1) / 2 * d2 + d2* (d2-1)/2 *d1; return ret; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { a[i][j]=readint(); } } for(int i=1;i<=n;i++) { top=0; for(int j=1;j<=m;j++) { while(top && a[i][stk[top-1]] > a[i][j]) --top; if(top==0) L[i][j]=1; else L[i][j]=stk[top-1]+1; stk[top++]=j; } } for(int i=1;i<=n;i++) { top=0; for(int j=m;j>=1;--j) { while(top && a[i][stk[top-1]] > a[i][j]) --top; if(top==0) R[i][j]=m; else R[i][j] = stk[top-1] - 1; stk[top++] = j; } } for(int i=1;i<=m;i++) { top=0; for(int j=1;j<=n;j++) { while(top && a[stk[top-1]][i] < a[j][i]) --top; if(top==0) U[j][i]=1; else U[j][i] = stk[top-1]+1; stk[top++]=j; } } for(int i=1;i<=m;i++) { top=0; for(int j=n;j>=1;--j) { while(top && a[stk[top-1]][i] < a[j][i]) --top; if(top==0) D[j][i]=n; else D[j][i] = stk[top-1]-1; stk[top++]=j; } } unsigned int ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { ans += (unsigned int)a[i][j]*calc(L[i][j],j,R[i][j])*calc(U[i][j],i,D[i][j]); } } printf("%u\n",ans); } return 0; }
HDU 5749 BestCoder Round #84 Colmerauer(暴力贡献)
标签:
原文地址:http://blog.csdn.net/liangzhaoyang1/article/details/52021953