洛谷 P6503 [COCI 2010/2011 #3] DIFERENCIJA 题解
题目链接
洛谷 P6503 [COCI 2010/2011 #3] DIFERENCIJA
题目大意
给定 \(a_{[1..n]}\),求下式值。
\[\sum_{i=1}^{n}\sum_{j=i}^{n}{(\max_{i\le k\le j}{a_k}-\min_{i\le k\le j}{a_k})}
\]
思路分析 - 1
采用动态规划。定义 \(f_i,g_i\) 分别表示以 \(i\) 结尾的所有子序列最大值之和与最小值之和,则题目所求即转换为 \(\sum_{i=1}^{n}{f_i-g_i}\)。
再定义 \(p_i\) 表示第一个满足 \(p<i\) 且 \(a_{p}>a_i\) 的 \(p\) 值,特别地,若 \(p\) 值不存在,则 \(p_i=0\)。根据定义,\(p_i\) 可以用一个单调栈维护。
再来看转移:
- 根据定义,序列 \(a_{[j..i]}\) 与 \(a_{[j..p_i]}\) 的最大值同为 \(a_{p_i}\) \((1\le j\le p_i)\),\(f_i\) 可以直接由 \(f_{p_i}\) 转移得到;
- 而序列 \(a_{[j..i]}\) 的最大值都为 \(a_i\) \((p_i<j\le i)\),所以 \(f_i\) 应加上 \(i-p_i\) 个 \(a_i\)。
综上,状态转移方程为:
\[f_i=f_{p_i}+a_i\times (i-p_i)
\]
对于 \(g_i\) 来说,同理,只需把定义中大于号改为小于即可。总时间复杂度 \(O(n)\)。
代码精讲 - 1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int n;
int a[N];
ll f[N],g[N];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",a+i);
stack<int> s,t;
for (int i=1;i<=n;++i){
while (!s.empty() && a[i]>=a[s.top()]) s.pop();
if (!s.empty()) f[i]=f[s.top()]+(i-s.top())*1ll*a[i]; // s.top() 即为 p[i]
else f[i]=i*1ll*a[i]; // 注意队列非空的特判
s.push(i);
while (!t.empty() && a[i]<=a[t.top()]) t.pop();
if (!t.empty()) g[i]=g[t.top()]+(i-t.top())*1ll*a[i];
else g[i]=i*1ll*a[i];
t.push(i);
}
ll ans=0;
for (int i=1;i<=n;++i) ans+=f[i]-g[i];
printf("%lld",ans);
return 0;
}
思路分析 - 2
首先将式子拆开。
\[\sum_{i=1}^{n}\sum_{j=i}^{n}{(\max_{i\le k\le j}{a_k}-\min_{i\le k\le j}{a_k})}=\sum_{i=1}^{n}\sum_{j=i}^{n}{\max_{i\le k\le j}{a_k}}-\sum_{i=1}^{n}\sum_{j=i}^{n}{\min_{i\le k\le j}{a_k}}
\]
我们只需考虑最大值部分,因为另一部分同理可得。
对于前一部分,我们考虑每个 \(a_i\) 会成为多少次最大值。定义 \(l_i\) 表示满足 \(a_{l_i}\le a_i\) 的最大下标,\(r_i\) 表示满足 \(a_{r_i}\ge a_i\) 的最小下标。则由定义 \(a_i\) 是 \(a_{[l_i,r_i]}\) 序列中的最大值。所以共有 \((i-l_i)\times(r_i-i)\) 个序列以 \(a_i\) 为最大值。
同时对于 \(l_i\) 和 \(r_i\) 可以利用单调栈预处理,总时间复杂度 \(O(n)\)。
代码精讲 - 2
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int n;
int a[N],l1[N],r1[N],l2[N],r2[N];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",a+i);
stack<int> s,t,u,v;
for (int i=1;i<=n;++i){ // 维护
while (!s.empty() && a[i]>=a[s.top()]) s.pop();
l1[i]=s.empty()?0:s.top();
s.push(i);
}
for (int i=n;i>=1;--i){
while (!t.empty() && a[i]>a[t.top()]) t.pop();
r1[i]=t.empty()?n+1:t.top();
t.push(i);
}
for (int i=1;i<=n;++i){
while (!u.empty() && a[i]<=a[u.top()]) u.pop();
l2[i]=u.empty()?0:u.top();
u.push(i);
}
for (int i=n;i>=1;--i){
while (!v.empty() && a[i]<a[v.top()]) v.pop();
r2[i]=v.empty()?n+1:v.top();
v.push(i);
}
ll ans=0;
for (int i=1;i<=n;++i) // 统计
ans+=a[i]*((i-l1[i])*1ll*(r1[i]-i)-(i-l2[i])*1ll*(r2[i]-i));
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号