【堆】B001_分级(大/小根堆分别维护升/降序序列)
给定长度为N的序列A,构造一个长度为N的序列B,满足:
- B非严格单调,即B1≤B2≤…≤BN或B1≥B2≥…≥BN。
- 最小化 S=∑Ni=1|Ai−Bi|。
只需要求出这个最小值S。
输入格式
第一行包含一个整数N。
接下来N行,每行包含一个整数Ai。
输出格式
输出一个整数,表示最小S值。
数据范围
1≤N≤2000,
0≤Ai≤109
输入样例:
7
1
3
2
4
5
3
9
输出样例:
3
方法一:大小根堆
用小根堆维护一个降序的序列B和用大根堆维护一个升序的序列B,具体为:
- 当维护一个升序序列时,当后面遍历到的元素x比大根堆maxQ的堆顶元素还要小的话,那就要对x做出调整,增量为
maxQ.top()-x
- 当维护一个降序序列时,当后面遍历到的元素x比小根堆minQ的堆顶元素还要大的话,那也要对x做出调整,减量为
x-minQ.top()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
ll n, ans1=0, ans2=0; cin>>n;
int A[n]; for (int i=0; i<n; i++) cin>>A[i];
priority_queue<ll> maxQ;
priority_queue<ll, vector<ll>, greater<int>> minQ;
for (ll x : A) { //维护升序序列
maxQ.push(x);
if (x<maxQ.top()) {
ans1+=maxQ.top()-x;
maxQ.pop(), maxQ.push(x);
}
}
for (ll x : A) { //维护降序序列
minQ.push(x);
if (x>minQ.top()) {
ans2+=x-minQ.top();
minQ.pop(), minQ.push(x);
}
}
cout << min(ans1, ans2);
return 0;
}
复杂度分析
- Time:\(O(nlogn)\),
- Space:\(O(n)\),