卧薪尝胆,厚积薄发。
POI2008 KLO-Building blocks
Date: Mon Sep 17 23:49:50 CST 2018 In Category: NoCategory

Description:

$n$ 柱砖,可以去掉一柱中的一个或者往一柱里放一个,使有连续 $k$ 个高度相同,问最少操作次数。
$1\le n \le 100000$

Solution:

可以枚举每个长为 $k$ 的区间,对于这个区间最后变成的数一定是整个区间中位数,于是用权值线段树求出中位数再求操作次数,我懒所以只写了一个 $\text{query}$ 同时计算两个。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,k;
typedef long long ll;
#define MAXN 100010
ll a[MAXN];
#define MAXP 1000010
struct node
{
int lc,rc;
ll sum;
int tot;
node(){sum = tot = 0;}
}t[MAXP << 1];
int ptr = 0;
int newnode(){return ++ptr;}
int root;
#define mid ((l + r) >> 1)
void build(int &rt,int l,int r)
{
rt = newnode();
if(l == r)return;
build(t[rt].lc,l,mid);
build(t[rt].rc,mid + 1,r);
return;
}
void insert(int rt,int p,int val,int l,int r)
{
if(l == r)
{
t[rt].tot += val;
t[rt].sum += val * p;
return;
}
if(p <= mid)insert(t[rt].lc,p,val,l,mid);
else insert(t[rt].rc,p,val,mid + 1,r);
t[rt].tot = t[t[rt].lc].tot + t[t[rt].rc].tot;
t[rt].sum = t[t[rt].lc].sum + t[t[rt].rc].sum;
return;
}
#define fi first
#define se second
pair<int,ll> query(int rt,int p,int l,int r)
{
if(l == r)return make_pair(l,0ll);
if(p > t[t[rt].lc].tot)
{
pair<int,ll> res = query(t[rt].rc,p - t[t[rt].lc].tot,mid + 1,r);
return make_pair(res.first,res.se + (ll)res.fi * (ll)t[t[rt].lc].tot - t[t[rt].lc].sum);
}
else
{
pair<int,ll> res = query(t[rt].lc,p,l,mid);
return make_pair(res.first,res.se + t[t[rt].rc].sum - (ll)res.fi * (ll)t[t[rt].rc].tot);
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;++i)scanf("%lld",&a[i]);
build(root,0,1000000);
for(int i = 1;i <= k;++i)insert(root,a[i],1,0,1000000);
ll ans = 0x3f3f3f3f3f3f3f3f;
pair<int,ll> res = query(root,(k + 1) / 2,0,1000000);
ans = res.se;
int pos = 1;
ll num = res.fi;
for(int i = k + 1;i <= n;++i)
{
insert(root,a[i],1,0,1000000);
insert(root,a[i - k],-1,0,1000000);
res = query(root,(k + 1) / 2,0,1000000);
if(res.se < ans){ans = res.se;pos = i - k + 1;num = res.fi;}
}
cout << ans << endl;
for(int i = 1;i <= n;)
{
if(i == pos){for(int j = 1;j <= k;++j)printf("%lld\n",num);i += k;}
else{printf("%lld\n",a[i]);++i;}
}
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡