贪心+树状数组,CF1579E2 - Array Optimization by Deque

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

1579E2 - Array Optimization by Deque

二、解题报告

1、思路分析

很好想也很好证明的贪心

因为添加的顺序是确定的,我们每次只需决策放左边还是放右边

x放左边,那么贡献就是右边比x小的个数

x放右边,那么贡献就是左边比x大的个数

两个位置,哪个贡献少放哪边

证明:反证法

假设存在最优解,存在a[i] 没有按照贪心策略放置,不妨假设应该放左边P1但是放了右边P2

那么我们将操作修改把a[i]放左边P1,其它操作不变

那么a[i]只影响了a[P1 + 1, P2 - 1]之间的数字的贡献

由于贪心策略是放P1,所以区间内比a[i]小的个数小于等于比a[i]大的个数,所以贡献不会变大

我们不断调整最优解中不是贪心策略的操作能够得到另一个最优甚至更优解。

证毕

由于值域很大需要离散化

2、复杂度

时间复杂度:O(NlogN) 空间复杂度:O(N)

3、代码详解

#include <bits/stdc++.h>
using PII = std::pair<int, int>;
using i64 = long long;
 
const int inf = 1e9;

template<typename T = int>
class FenWick {
private:
    T n;
    std::vector<T> tr;
public:
    FenWick(T _n) : n(_n), tr(_n + 1) 
    {}

    void add(T x, T k) {
        for (; x <= n; x += x & -x) tr[x] += k;
    }

    T query(T x) const {
        T res = 0;
        for (; x; x &= x - 1) res += tr[x];
        return res;
    }
};
 
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> nums(n);
    for (int i = 0; i < n; i ++ ) std::cin >> nums[i];
    std::vector<int> id(nums);
    std::sort(id.begin(), id.end());
    id.erase(std::unique(id.begin(), id.end()), id.end());
    int m = id.size();
    
    FenWick<int> st(m + 1);

    i64 res = 0;
    for (int x : nums) {
        x = std::lower_bound(id.begin(), id.end(), x) - id.begin() + 1;
        int L = st.query(x - 1), R = st.query(m) - st.query(x);
        st.add(x, 1);
        res += std::min(L, R);
    }
    std::cout << res << '\n';
}
 
 
int main () {
    std::ios::sync_with_stdio(false);   std::cin.tie(0);  std::cout.tie(0);
    int _ = 1;
    std::cin >> _;
    while (_ --)
        solve();
    return 0;
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值