HDU 5749 Colmerauer 单调队列+暴力贡献

BestCoder Round #84   1003

分析:(先奉上zimpha巨官方题解)

感悟:看到题解单调队列,秒懂如何处理每个点的范围,但是题解的一句算贡献让我纠结半天

        已知一个点的up,down,left,right,即上下左右的扩展范围,如何确定贡献呢

        其实也很好做,把所有可能的矩形的长算出来,得到和,宽也是一样,然后乘法原理乘起来就好

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <stack>
#include <map>
using namespace std;
typedef long long LL;
const int N = 1e3+5;
const int INF = 0x3f3f3f3f;
const LL mod = 1ll<<32;
int a[N][N],l[N][N],r[N][N],u[N][N],d[N][N];
int T,n,m;
stack<int>s;
LL cal(LL x,LL y){
  return (x*(x+1)/2*y%mod+y*(y-1)/2*x%mod)%mod; 
}
int main(){
  scanf("%d",&T);
  while(T--){
     scanf("%d%d",&n,&m);
     for(int i=1;i<=n;++i)
      for(int j=1;j<=m;++j)
        scanf("%d",&a[i][j]);
     for(int i=1;i<=n;++i){
        a[i][m+1]=a[i][0]=-INF;
        while(!s.empty())s.pop();s.push(0);
        for(int j=1;j<=m;++j){
          while(!s.empty()&&a[i][s.top()]>a[i][j])s.pop();
          l[i][j]=s.top();s.push(j);
        }
        while(!s.empty())s.pop();s.push(m+1);
        for(int j=m;j;--j){
          while(!s.empty()&&a[i][s.top()]>a[i][j])s.pop();
          r[i][j]=s.top();s.push(j);
        }
     }
     for(int j=1;j<=m;++j){
       a[0][j]=a[n+1][j]=INF;
       while(!s.empty())s.pop();s.push(0);
       for(int i=1;i<=n;++i){
        while(!s.empty()&&a[s.top()][j]<a[i][j])s.pop();
        u[i][j]=s.top();s.push(i);
       }
       while(!s.empty())s.pop();s.push(n+1);
       for(int i=n;i;--i){
         while(!s.empty()&&a[s.top()][j]<a[i][j])s.pop();
         d[i][j]=s.top();s.push(i);
       }
     }
     LL ret=0;
     for(int i=1;i<=n;++i)
      for(int j=1;j<=m;++j){
        LL curl=j-l[i][j],curr=r[i][j]-j;
        LL curu=i-u[i][j],curd=d[i][j]-i;
        ret+=cal(curl,curr)*cal(curu,curd)%mod*a[i][j]%mod;
        ret%=mod;
      }
     printf("%I64d
",ret);
  }
  return 0;
}
View Code
原文地址:https://www.cnblogs.com/shuguangzw/p/5700975.html