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
原题还要求输出结束状态时,每柱砖的高度.本题略去.
Solution
问题可以这么描述为,求一个数x和一个区间[l...r],使sum_{i=l}^{r}{x-a_i}最小。
容易想到的是这个x就是区间[l...r]的中位数。
那么现在就需要一个数据结构快速维护带插入删除的中位数,使用fhq-treap即可。
然后我的板子奇奇怪怪的需要一个虚点来当根所以中位数是k>>1+2...
注意要开longlong,以及,如果偷懒使用define int longlong的时候一定要在代码的最上方,至少要在读优的上方!!!!!!!!!!!!!!!!!
#include <bits/stdc++.h> #define ll long long #define inf 0x7ffffffff #define il inline #define debug puts("233") #define int long long namespace io { #define in(a) a=read() #define out(a) write(a) #define outn(a) out(a),putchar(' ') #define I_int int inline I_int read() { I_int x = 0 , f = 1 ; char c = getchar() ; while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; } while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; } return x * f ; } char F[ 200 ] ; inline void write( I_int x ) { if( x == 0 ) { putchar( '0' ) ; return ; } I_int tmp = x > 0 ? x : -x ; if( x < 0 ) putchar( '-' ) ; int cnt = 0 ; while( tmp > 0 ) { F[ cnt ++ ] = tmp % 10 + '0' ; tmp /= 10 ; } while( cnt > 0 ) putchar( F[ -- cnt ] ) ; } #undef I_int } using namespace io ; using namespace std ; #define N 100010 int n , k , root = 1 ,tot = 0; struct fhq { int siz , val , rnk , lc , rc , sum ; }t[N]; void up(int rt) { t[rt].siz = t[t[rt].lc].siz + t[t[rt].rc].siz + 1; t[rt].sum = t[t[rt].lc].sum + t[t[rt].rc].sum + t[rt].val; } void split(int &a , int &b , int val , int rt) { if(!rt) { a = b = 0; return; } if(t[rt].val <= val) a = rt , split(t[a].rc , b , val , t[rt].rc) ; else b = rt , split(a , t[b].lc , val , t[rt].lc) ; up(rt); } void merge(int a , int b , int &rt) { if(!a || !b) { rt = a + b; return; } if(t[a].rnk < t[b].rnk) rt = a , merge(t[a].rc , b , t[rt].rc) ; else rt = b , merge(a , t[b].lc , t[rt].lc) ; up(rt); } int new_node(int val) { t[++tot] = (fhq) {1 , val , rand() , 0 , 0 , val} ; return tot ; } void insert(int val) { int x = 0 , y = 0 , z = new_node(val) ; split(x , y , val - 1, root) ; merge(x , z , x) ; merge(x , y , root) ; } void erase(int val) { int x = 0 , y = 0 , z = 0; split(x , y , val , root); split(x , z , val - 1 , x); merge(t[z].lc , t[z].rc , z) ; merge(x , z , x) ; merge(x , y , root) ; } int find_kth(int rnk , int rt) { while(1) { if(t[t[rt].lc].siz + 1 < rnk) rnk -= t[t[rt].lc].siz + 1, rt = t[rt].rc; else if(t[t[rt].lc].siz >= rnk) rt = t[rt].lc ; else return t[rt].val; } } void print(int rt) { if(t[rt].lc) print(t[rt].lc) ; cout<<t[rt].val<<" "; if(t[rt].rc) print(t[rt].rc) ; } int query(int val) { int x = 0 , y = 0 , z = 0 ; split(x , y , val , root) ; split(x , z , val - 1 , x) ; int s1 = 1ll * (t[x].siz - 1)* val , s2 = 1ll * t[y].siz * val ; int a1 = t[x].sum , a2 = t[y].sum ; // cout<<a1<<" "<<a2<<" "<<endl; merge(x , z , x) ; merge(x , y , root) ; // cout<<s1-a1+a2-s2<<endl; return s1 - a1 - s2 + a2 ; } int a[N] ; signed main() { /* freopen("1112.in","r",stdin); freopen("1112.out","w",stdout);*/ srand((unsigned)time(0)) ; n = read() , k = read() ; new_node(0) ; t[1].siz = 0 ; for(int i = 1 ; i <= n ; i ++) a[i] = read() ; ll ans = 2e18 , M = 0 , L = 0 , R = 0; a[0] = 0; for(int i = 0 ; i < k ; i ++) insert(a[i]) ; int l = 0 , r = k - 1 ; while(r < n) { ++l , ++r ; erase(a[l - 1]) ; insert(a[r]) ; int mid = find_kth((k>>1)+2 , root) ; ll tmp = query(mid) ; if(tmp < ans) { M = mid ; L = l ; R = r; ans = tmp; } // print(root);puts(""); // cout<<l<< " "<<r<<" "<<mid<<endl; } outn(ans); /* for(int i = 1 ; i < L ; i ++) outn(a[i]) ; for(int i = L ; i <= R; i ++) outn(M) ; for(int i = R + 1 ; i <= n; i ++) outn(a[i]) ;*/ return 0; }