1. 程式人生 > >bzoj2259 [Oibh]新型計算機

bzoj2259 [Oibh]新型計算機

oid con ons sizeof 正整數 HA space CP 改變

[Oibh]新型計算機

Time Limit: 6 Sec Memory Limit: 128 MB

Description

Tim正在擺弄著他設計的“計算機”,他認為這臺計算機原理很獨特,因此利用它可以解決許多難題。
但是,有一個難題他卻解決不了,是這臺計算機的輸入問題。新型計算機的輸入也很獨特,假設輸入序列中有一些數字(都是自然數——自然數包括0),計算機先讀取第一個數字S1,然後順序向後讀入S1個數字。接著再讀一個數字S2,順序向後讀入S2個數字……依此類推。不過只有計算機正好將輸入序列中的數字讀完,它才能正確處理數據,否則計算機就會進行自毀性操作!
Tim現在有一串輸入序列。但可能不是合法的,也就是可能會對計算機造成破壞。於是他想對序列中的每一個數字做一些更改,加上一個數或者減去一個數,當然,仍然保持其為自然數。使得更改後的序列為一個新型計算機可以接受的合法序列。

不過Tim還希望更改的總代價最小,所謂總代價,就是對序列中每一個數操作的參數的絕對值之和。
寫一個程序:
? 從文件中讀入原始的輸入序列;
? 計算將輸入序列改變為合法序列需要的最小代價;
? 向輸出文件打印結果。

Input

輸入文件包含兩行,第一行一個正整數N,N<1 000 001。
輸入文件第二行包含N個自然數,表示輸入序列。

Output

僅一個整數,表示把輸入序列改變為合法序列需要的最小代價,保證最小代價小於109。

Sample Input

4

2 2 2 2

Sample Output

1




\(f[i]\) 表示處理 \(i\)\(n\) 的最優答案。
顯然 \(f[i] = min \{ f[j] + abs{(j - i - 1) - a[i]} \}\ \ \ (i<j<n)\)


我們把這個式子打開
\(f[i] = min(f[j]+j)-(i+1+a[i])\ \ \ (j ≥ a[i]+i+1)\)
\(f[i] = min(f[j]-j)+(i+1+a[i])\ \ \ (j<a[i]+i+1)\)
然後我們分別用兩個樹狀數組維護一下 \(f[j]+j\)\(f[j]-j\) 就好了


#include<bits/stdc++.h>
#define lowbit(x) ((x) & (-x))
using namespace std;
const int maxn = 1e6 + 6, INF = 1e9 + 9;
int n, ini[maxn], f[maxn], tree1[maxn], tree2[maxn];

inline
int read() { char ch = getchar(); int x = 0, f = 1; while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} while('0' <= ch && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();} return x * f; } inline int query2(int t) { int ret = INF; if(t > n || t <= 0) return ret; while(t){ ret = min(ret, tree2[t]); t -= lowbit(t); } return ret; } inline int query1(int t) { int ret = INF; t = (n + 1) - t; if(t > n || t <= 0) return ret; while(t){ ret = min(ret, tree1[t]); t -= lowbit(t); } return ret; } inline void Modify(int t) { int lin = t; while(lin <= n){ tree2[lin] = min(tree2[lin], f[t] - t); lin += lowbit(lin); } lin = (n + 1) - t; while(lin <= n){ tree1[lin] = min(tree1[lin], f[t] + t); lin += lowbit(lin); } } int main() { scanf("%d", &n); int t; memset(tree1, 0x3f, sizeof(tree1)); memset(tree1, 0x3f, sizeof(tree1)); for(int i = 1; i <= n; ++i) ini[i] = read(); for(int i = n; i >= 1; --i){ f[i] = abs(n - i - ini[i]); t = ini[i] + i + 1; if(t < n) f[i] = min(f[i], query1(t) - t); f[i] = min(f[i], query2(t) + t); Modify(i); } cout << f[1]; return 0; }

bzoj2259 [Oibh]新型計算機