BZOJ 1112: [POI2008]砖块Klo

1112: [POI2008]砖块Klo

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1736  Solved: 606
[Submit][Status][Discuss]

Description

N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

Input

第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000

Output

最小的动作次数

Sample Input

5 3

3

9

2

3

1

Sample Output

2

HINT

原题还要求输出结束状态时,每柱砖的高度.本题略去.

Source

[Submit][Status][Discuss]

分析

对于一段区间,可以知道将高度改为中位数是最优的,因此我们需要做的是维护一个区间的中位数,以及小于中位数的数字之和和大于中位数的数字之和,这个可以平衡树,可以树状数组+二分查找,或者是线段树上二分,甚至是STL set,做法太多……

代码

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <iostream>
  6 #include <algorithm>
  7
  8 #define ri register int
  9
 10 #define lim 10000000
 11
 12 char *c = new char[lim];
 13
 14 template <class T>
 15 void read(T &x)
 16 {
 17     x = 0;
 18
 19     while (*c < ‘0‘)++c;
 20
 21     while (*c >= ‘0‘)
 22         x = x*10 + *c++ - ‘0‘;
 23 }
 24
 25 template <class T>
 26 void Min(T &a, T b)
 27 {
 28     if (a > b)a = b;
 29 }
 30
 31 template <class T>
 32 void Max(T &a, T b)
 33 {
 34     if (a < b)a = b;
 35 }
 36
 37 #define N 1000005
 38
 39 int n, m;
 40 int h[N];
 41
 42 struct node
 43 {
 44     int lt, rt, cnt;
 45     long long sum;
 46 }tree[N * 6];
 47
 48 void build(int p, int l, int r)
 49 {
 50     node &t = tree[p];
 51
 52     t.lt = l;
 53     t.rt = r;
 54
 55     t.cnt = t.sum = 0;
 56
 57     if (l ^ r)
 58     {
 59         int mid = (l + r) >> 1;
 60
 61         build(p << 1, l, mid);
 62         build(p << 1 | 1, mid + 1, r);
 63     }
 64 }
 65
 66 void insert(int p, int pos, int val1, int val2)
 67 {
 68     node &t = tree[p];
 69
 70     t.cnt += val1;
 71     t.sum += val2;
 72
 73     if (t.lt ^ t.rt)
 74     {
 75         int mid = (t.lt + t.rt) >> 1;
 76
 77         if (pos <= mid)
 78             insert(p << 1, pos, val1, val2);
 79         else
 80             insert(p << 1 | 1, pos, val1, val2);
 81     }
 82 }
 83
 84 int query1(int p, int rank)
 85 {
 86     node &t = tree[p];
 87
 88     if (t.lt == t.rt)return t.lt;
 89
 90     if (tree[p << 1].cnt >= rank)
 91         return query1(p << 1, rank);
 92     else
 93         return query1(p << 1 | 1, rank - tree[p << 1].cnt);
 94 }
 95
 96 long long query2(int p, int l, int r)
 97 {
 98     if (l > r)return 0LL;
 99
100     node &t = tree[p];
101
102     if (l == t.lt && r == t.rt)
103         return t.sum;
104
105     int mid = (t.lt + t.rt) >> 1;
106
107     if (r <= mid)
108         return query2(p << 1, l, r);
109     if (l > mid)
110         return query2(p << 1 | 1, l, r);
111     return query2(p << 1, l, mid) + query2(p << 1 | 1, mid + 1, r);
112 }
113
114 int query3(int p, int l, int r)
115 {
116     if (l > r)return 0LL;
117
118     node &t = tree[p];
119
120     if (l == t.lt && r == t.rt)
121         return t.cnt;
122
123     int mid = (t.lt + t.rt) >> 1;
124
125     if (r <= mid)
126         return query3(p << 1, l, r);
127     if (l > mid)
128         return query3(p << 1 | 1, l, r);
129     return query3(p << 1, l, mid) + query3(p << 1 | 1, mid + 1, r);
130 }
131
132 signed main(void)
133 {
134     fread(c, 1, lim, stdin);
135
136     read(n);
137     read(m);
138
139     ri maxi = 0;
140     ri mini = N;
141
142     for (ri i = 1; i <= n; ++i)
143     {
144         read(h[i]);
145
146         Min(mini, h[i]);
147         Max(maxi, h[i]);
148     }
149
150     build(1, 0, N);
151
152     for (ri i = 1; i < m; ++i)
153         insert(1, h[i], 1, h[i]);
154
155     int d = (m + 1) >> 1;
156
157     long long ans = 1e18 + 9;
158
159     for (ri i = m; i <= n; ++i)
160     {
161         insert(1, h[i], 1, h[i]);
162
163         {
164             int mid = d;
165
166             long long q = query1(1, mid), res = 0LL;
167
168             long long lc = query3(1, 0, q - 1);
169             long long rc = query3(1, q + 1, N);
170
171             res += lc*q - query2(1, 0, q - 1);
172             res += query2(1, q + 1, N) - rc*q;
173
174             Min(ans, res);
175         }
176
177         insert(1, h[i - m + 1], -1, -h[i - m + 1]);
178     }
179
180     printf("%lld\n", ans);
181 }

BZOJ_1112.cpp

@Author: YouSiki

时间: 2024-10-13 01:31:33

BZOJ 1112: [POI2008]砖块Klo的相关文章

[BZOJ 1112] [POI2008] 砖块Klo 【区间K大】

题目链接:BZOJ - 1112 题目分析 枚举每一个长度为k的连续区间,求出这个区间的最优答案,更新全局答案. 可以发现,这个区间的所有柱子最终都变成这k个数的中位数时最优,那么我们就需要查询这个区间的中位数了. 找到中位数之后,我们还应该求出这个区间内小于中位数的数的和,大于中位数的数的和,从而求出操作步数. 这些需要求的值可以用线段树或平衡树来写,我写的是线段树,但是实际上这是一道POI的题目,在MAIN上的空间限制只有35MB,线段树应该是不行的. 因为平衡树只需要 O(n) 空间,所以

BZOJ 1112 [POI2008]砖块Klo(可持久化线段树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1112 [题目大意] 给出一个数列,对于一个操作,你可以对一个数+1,或者一个数-1, 问若使得数列中出现长度为m的连续相同的数,最少需要的操作数. [题解] 我们发现对于固定区间求最小操作,等价于求区间中数距离中位数差值和最小, 我们发现区间中位数可以利用主席树求区间kth来实现, 同时在主席树上维护权值线段树的区间真值和,那么对于每个区间中的数, 就能分别维护比中位数小的部分的和以

1112: [POI2008]砖块Klo

1112: [POI2008]砖块Klo Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1245  Solved: 426[Submit][Status][Discuss] Description N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务. Input 第一行给出N,K. (1 ≤ k ≤ n ≤

BZOJ 1112: [POI2008]砖块Klo1112( BST )

枚举每个长度为k的区间, 然后用平衡树找中位数进行判断, 时间复杂度O(nlogn). 早上起来精神状态不太好...连平衡树都不太会写了...果断去看了会儿番然后就A了哈哈哈 -------------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; i++) #define clr(x,

bzoj1112[POI2008]砖块Klo*

bzoj1112[POI2008]砖块Klo 题意: N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:丢掉某柱砖的一块砖.给某柱加上一块砖,现在希望用最小次数的动作完成任务.N≤100000 题解: 设一个区间长度为k,其中位数为a,比a小的元素个数为b,和为c:比a大的元素个数为d,和为e.则题目要求维护一个长度为k的滑动窗口,能求出它的b*a-c+e-d*a.故用一个维护sum,size两个值的treap来维护.然而似乎我想复杂了?比所有人代码都大1k!注意要开long

[BZOJ1112] [POI2008] 砖块Klo (treap)

Description N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务. Input 第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000 Output 最小的动作次数 Sample Input 5 3 3 9 2 3 1 Sample Output 2 HINT 原题还要求输

【枚举】【权值分块】bzoj1112 [POI2008]砖块Klo

枚举长度为m的所有段,尝试用中位数更新答案. 所以需要数据结构,支持查询k大,以及大于/小于 k大值 的数的和. 平衡树.权值线段树.权值分块什么的随便呢. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 using namespace std; 5 typedef long long ll; 6 struct Point{int v,p;}t[100001]; 7 bool operator &

【bzoj1112】[POI2008]砖块Klo Treap

题目描述 N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务. 输入 第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000 输出 最小的动作次数 样例输入 5 3 3 9 2 3 1 样例输出 2 题解 Treap 根据某数学定理,∑|ai-x|最小时x为ai的中位数. 那么我们可

bzoj 1112 poi 2008 砖块

这滞胀题调了两天了... 好愚蠢的错误啊... 其实这道题思维比较简单,就是利用treap进行维护(有人说线段树好写,表示treap真心很模板) 就是枚举所有长度为k的区间,查出中位数,计算代价即可. (根据绝对值不等式的几何意义,中位数一定是最优解) 而维护长度为k的区间也很简单,就是首先把前k个扔到树上,然后每次把新来的插入,把最前面的一个删除即可 至于求中位数,简直就是基础操作嘛 关键在于...代价怎么算? 显然我们不能把所有数枚举出来挨个加减,这样会T飞的... 所以我们考虑直接在tre