【堆】B001_分级(大/小根堆分别维护升/降序序列)

给定长度为N的序列A,构造一个长度为N的序列B,满足:

  1. B非严格单调,即B1≤B2≤…≤BN或B1≥B2≥…≥BN。
  2. 最小化 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)\)
posted @ 2020-09-08 08:48  童年の波鞋  阅读(251)  评论(0编辑  收藏  举报