题意
给你
n
n
n个矩形,从左到右排列,第
i
i
i个矩形的高和宽分别为
h
i
{h_i}
hi和
w
i
{w_i}
wi,计算其中包含的所有长方形的数量,对
1
0
9
+
7
{10^9+7}
109+7取模。例如图1所示包含
12
12
12个长方形。
分析
首先一个宽度为
w
w
w,高为
h
h
h的矩形所包含的长方形的数量为
C
w
+
1
2
⋅
C
h
+
1
2
C_{w + 1}^2 \cdot C_{h + 1}^2
Cw+12⋅Ch+12(可以看做
w
+
1
w + 1
w+1和
h
+
1
h+1
h+1个点中分别选择
2
2
2个点构成长方形)。如果所有矩形的高度递增,那么可以按照如下方法计算矩形数量:
每次都计算黄色部分矩形所包含的长方形数量减去阴影部分所包含的长方形数量求和即可。如果不是高度递增的情况,如下所示:
当某时矩形的高度小于之前矩形的高度,如图所示,高度大于绿色矩形高度的矩形都不可能再与后面的矩形形成长方形,因此我们将黄色部分矩形所包含的长方形数量累加(按照上面递增的方法做即可),弹出高度大于绿色矩形高度的矩形(黄色部分),同时将弹出矩形的宽度累加到绿色矩形上。这其实就是单调栈的操作过程,我们维护一个高度递增的栈即可。需要注意的是在弹出所有矩形之后还需要减去阴影部分的长方形,避免重复,同时在写代码的时候可以在最后添加一个高度为
0
0
0的矩形,将栈清空。
代码
#include<bits/stdc++.h>
#define ll long long
#define FULL(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
const ll mod=1e9+7, inv2=(mod+1)/2;
const int N=100005;
int n;
ll w[N],h[N];
ll cal(ll w, ll h) {
w=w%mod,h=h%mod;
ll ans=(((w+1)*w)%mod*inv2)%mod;
ans=(ans*((((h+1)*h)%mod*inv2)%mod))%mod;
return ans;
}
int main() {
cin>>n;
for(int i=1;i<=n;i++) cin>>h[i];
for(int i=1;i<=n;i++) cin>>w[i];
vector<ll> v;
ll ans=0;
for(int i=1;i<=n+1;i++) {
ll tmp=0;
while(v.size() && h[v[v.size()-1]]>h[i]) {
//do
int x=v[v.size()-1];
v.pop_back();
//left:w[x],right:tmp
ans=(ans+cal(w[x]+tmp,h[x]))%mod;
ans=(ans-cal(tmp,h[x])+mod)%mod;
tmp=(tmp+w[x])%mod;
}
ans=(ans-cal(tmp,h[i])+mod)%mod;
w[i]=(w[i]+tmp)%mod;
v.pb(i);
}
cout<<ans;
return 0;
}