洛谷P3466 [POI2008] KLO-Building blocks(双set动态维护中位数)

P3466 [POI2008] KLO-Building blocks - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=O83Ahttps://www.luogu.com.cn/problem/P3466

在线维护中位数,大于等于中位数的放到一个set里,小于中位数的放到另一个set里。如果两个set大小不同就调整一下。

注意,n=1时需要特判。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int N = 1e5 + 5, M = 5e2 + 5, base = 131;
const int inf = 0x3f3f3f3f3f3f3f3f, MOD = 1e9 + 7;
int n, k, mid;
int a[N];
multiset<int>st1, st2;
multiset<int>::iterator it;
void solve()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    if (n == 1)
    {
        cout << 0 << endl;
        cout << a[1] << endl;
        return;
    }
    int res1 = 0, res2 = 0;
    mid = a[1], st2.insert(a[1]), res2 += a[1];
    int ans = inf, ansmid = 0, idx = 0;
    for (int i = 2; i <= n; i++)
    {
        if (i > k)
        {
            if (a[i - k] >= mid) st2.erase(st2.find(a[i - k])), res2 -= a[i - k];
            else st1.erase(st1.find(a[i - k])), res1 -= a[i - k];
        }
        if (a[i] >= mid) st2.insert(a[i]), res2 += a[i];
        else st1.insert(a[i]), res1 += a[i];
        while (st1.size() + 1 < st2.size())
        {
            it = st2.begin();
            res2 -= *it;
            res1 += *it;
            st1.insert(*it);
            st2.erase(it);
        }
        while (st1.size() > st2.size())
        {
            it = prev(st1.end());
            res1 -= *it;
            res2 += *it;
            st2.insert(*it);
            st1.erase(it);
        }
        mid = *st2.begin();
        if (i >= k)
        {
            int sum = 0;
            sum += (res2 - mid * (int)(st2.size()));
            sum += (mid * (int)(st1.size()) - res1);
            if (ans >= sum)
            {
                ans = sum;
                ansmid = mid;
                idx = i;
            }
        }
    }
    cout << ans << endl;
    for (int i = idx - k + 1; i <= idx; i++) a[i] =  ansmid;
    for (int i = 1; i <= n; i++)
    {
        cout << a[i] << endl;
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    // cin >> T;
    for (int i = 1; i <= T; i++)
    {
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值