BZOJ 1112: [POI2008]砖块Klo
1112: [POI2008]砖块Klo
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 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
3
9
2
3
1
Sample Output
2
HINT
原题还要求输出结束状态时,每柱砖的高度.本题略去.
Source
分析
对于一段区间,可以知道将高度改为中位数是最优的,因此我们需要做的是维护一个区间的中位数,以及小于中位数的数字之和和大于中位数的数字之和,这个可以平衡树,可以树状数组+二分查找,或者是线段树上二分,甚至是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 }
@Author: YouSiki