嘟嘟嘟ios
這道題要是直接想正解實在太難了,還得從一些特殊的狀況一點點入手。git
1.若是ai自己就是遞增的,那麼令bi = ai即最優解。數據結構
2.若是ai嚴格遞減,則b1 = b2 = b3 = ……= bn = 中位數爲最優解。這個能夠用初中的幾何證實:把 |bi - ai| 想象成數軸上兩點間距離,那麼 |x - a1| + |x - a2|的最優解x必定a1和a2之間;擴展到三項:|x - a1| + |x - a2| + |x - a3|,那麼x就是中位數;以此類推,x是中位數得證。ide
如今再想一想通常狀況:對於數列{an},可能有一段遞增,有一段遞減,那麼就把這些當作一段一段的:初始每一段的長度都爲1,令中位數爲ci,則ci = ai。若ci < ci+1,那麼就保持不變;不然將ci和ci+1所在的區間合併,取一個新的中位數,做爲新區間的答案。就這樣不斷的合併,直到ci不降低。優化
所以咱們須要一個數據結構,支持合併、查詢最大值和刪除。爲何要查詢最大值和刪除呢?由於維護中位數能夠只維護⌈1/2區間長度⌉小的數,用一個大根堆,則堆頂就是中位數。合併完兩個區間後,就一直刪除堆頂,直到元素個數 = ⌈1/2區間長度⌉。spa
那麼就能想到用左偏樹實現啦。因此左偏樹並非這道題的核心,實際上只起到了一個優化的做用。code
最後一點,就是題中讓求的是嚴格遞增,然而咱們一直是在不降低的前提下思考的。有一個巧妙的作法,就是開始ai -= i,就轉換成了不降低。blog
代碼稍微參考了別人的題解(左偏樹仍是不太熟啊)。get
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 1e6 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 27 if(last == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar('-'); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int n; 38 39 struct Node 40 { 41 int root, l, r, siz; 42 ll val; 43 }st[maxn]; 44 int top = 0; 45 46 ll val[maxn]; 47 int dis[maxn], ls[maxn], rs[maxn]; 48 int merge(int x, int y) 49 { 50 if(!x || !y) return x | y; 51 if(val[x] < val[y]) swap(x, y); 52 rs[x] = merge(rs[x], y); 53 if(dis[rs[x]] > dis[ls[x]]) swap(rs[x], ls[x]); 54 dis[x] = dis[rs[x]] + 1; 55 return x; 56 } 57 int Del(int x) 58 { 59 return merge(ls[x], rs[x]); 60 } 61 62 ll ans = 0; 63 64 int main() 65 { 66 n = read(); 67 for(int i = 1; i <= n; ++i) val[i] = read() - i; 68 st[++top] = (Node){1, 1, 1, 1, val[1]}; 69 for(int i = 2; i <= n; ++i) 70 { 71 st[++top] = (Node){i, i, i, 1, val[i]}; 72 while(top && st[top].val < st[top - 1].val) 73 { 74 top--; 75 st[top].root = merge(st[top].root, st[top + 1].root); 76 st[top].siz += st[top + 1].siz; 77 st[top].r = st[top + 1].r; 78 while(st[top].siz > (st[top].r - st[top].l + 1 + 1) >> 1) //向上取整 79 { 80 st[top].siz--; 81 st[top].root = Del(st[top].root); 82 } 83 st[top].val = val[st[top].root]; 84 } 85 } 86 for(int i = 1, j = 1; i <= n; ++i) 87 { 88 if(i > st[j].r) j++; 89 ans += abs(st[j].val - val[i]); 90 } 91 write(ans); enter; 92 for(int i = 1, j = 1; i <= n; ++i) 93 { 94 if(i > st[j].r) j++; 95 write(st[j].val + i), space; 96 } 97 enter; 98 return 0; 99 }