例. 營業額統計(湖南選拔賽)
[問題描述]
公司的賬本上記錄了公司成立以來每天的營業額。分析營業情況是一項相當複雜的工作,營業額會出現一定的波動,當然一定的波動是能夠接受的,但是在某些時候營業額突變得很高或是很低,這就證明公司此時的經營狀況出現了問題。經濟管理學上定義了一種最小波動值來衡量這種情況:
該天的最小波動值 = min{ | 改天以前某天的營業額 - 當天的營業額 | }
當最小波動值越大時,就說明營業情況越不穩定。
而分析整個公司的從成立到現在營業情況是否穩定,只需要把每一天的最小波動值加起來就可以了。你的任務就是編寫一個程式來計算這一個值。第一天的最小波動值為第一天的營業額。
輸入檔案第一行為正整數 n (n<=1000000),表示該公司從成立一直到現在的天數,接下來的 n 行每行有一個正整數,表示第i天公司的營業額。
輸出檔案僅有一個正整數,即。結果小於。
輸入輸出範例
[演算法分析]
本題題意明了,關鍵是讀入一個數,找到前面已經輸入的與此數相差最小的數。
題目的標準演算法是通過平衡樹來解決的,平衡樹,就是一種能自己進行適應,使樹的深度達到盡量小的一種檢索樹,詳細的情況可以參考相關書籍。
/*分析:由於 set 內部是平衡二叉樹,所有的操作都是lg(n) ,觀察資料知道此資料的 n 範圍很大,有必要採用 n*lg(n)*lg(n)的演算法 */ #include<iostream>#include<cstdio>#include<set>using namespace std;set<int>x;int main(){ int n,a; while(cin>>n){ x.clear(); scanf("%d",&a); int sum = a; x.insert(a); for(int i=1;i<n;i++){ scanf("%d",&a); if(a > *x.rbegin()){ //大於集合最大的元素 sum += a - *x.rbegin(); x.insert(a); continue; } if(x.find(a)!=x.end()) continue; if(a < *x.begin()){ //小於集合最小的元素 sum += *x.rbegin() - a; x.insert(a); continue; } int ans=*x.upper_bound(a); //第一次出現大於 a int left=0,ant,right=a; int mid = (left+right)>>1; while(1){ // 二分直接逼近 ant = *x.upper_bound(mid); if(*x.upper_bound(ant)==ans) break; if(ant >= ans){ right=mid-1; } else left=mid+1; mid = (left+right)>>1; } if(ans-a > a-ant) sum += a-ant; else sum += ans-a; x.insert(a); } cout<<sum<<endl; }}