★【左偏樹】Financial Fraud

來源:互聯網
上載者:User
Bernard Madoff is an American former stock broker, investment adviser, non-executive chairman of theNASDAQ stock market, and the admitted operator of what has been described as the largest Ponzi schemein history.Two programmers, Jerome O'Hara and George Perez, who helped Bernard Madoff program to produce falserecords have been indicted. They were accused of conspiracy, falsifying records of a broker dealerand falsifying records of an investment adviser.

In every quarter of these years, the two programmers would receive a data sheet, which provided aseries of profit records a1 a2 ... aN in that period. Due to the economic crisis, the awful recordsmight scare investors away. Therefore, the programmers were asked to falsifying these records intob1 b2 ... bN. In order to deceive investors, any record must be no less than all the records beforeit (it means for any 1 ≤ i < j ≤ N, bi ≤ bj).On the other hand, they defined a risk value for their illegal work: risk value = | a1 - b1 | +| a2 - b2 | + ... + | aN - bN | . For example, the original profit records are 300 400 200 100.If they choose 300 400 400 400 as the fake records, the risk value is 0 + 0 + 200 + 300 = 500.But if they choose 250 250 250 250 as the fake records, the risk value is 50 + 150 + 50 + 150 =400. To avoid raising suspicion, they need to minimize the risk value.Now we will give you some copies of the original profit records, you need to find out the minimalpossible risk value.InputThere are multiple test cases (no more than 20).For each test case, the first line contains one integer N (1 ≤ N ≤ 50000), the next line containsN integers a1 a2 ... aN (-109 ≤ ai ≤ 109). The input will end with N = 0.OutputFor each test case, print a single line that contains minimal possible risk value.Sample Input4300 400 200 1000Sample Output400

此題考察可並優先隊列的應用。

用左偏樹實現。

首先,考慮兩個極端的情況:
 1): 若a1 <= a2 <= ... <= an,那麼問題的解顯然是bi = ai(i = 1, 2, ..., n);
 2): 若a1 > a2 > ... > an,那麼問題的解是bi = x(x為序列a1, a2, ..., an的中位元)。

所以所有序列的解都不會差於中位元。

最終一定可以將整個序列劃分為若干個區間,使得每個區間的都為該區間的中位元。用左偏樹來維護每個區間的中位元,當前面一個區間的中位元大於該區間的中位元時,合并這兩棵左偏樹即可。

PS:ZOJ的測評系統為Linux,所以輸出64為整型要用“%lld”。

Accode:

#include <cstdio>#include <cstdlib>#include <algorithm>#include <string>#define abs(x) ((x) > 0 ? (x) : -(x))const int maxN = 50010;struct LeftList{    int key, dist;    LeftList *lc, *rc;    LeftList() {}    LeftList(int key):        key(key), dist(0),        lc(NULL), rc(NULL) {}};LeftList *tr[maxN];int L[maxN], R[maxN], sz[maxN], a[maxN];inline int getint(){    int res = 0; char tmp; bool sgn = 1;    do tmp = getchar();    while (!isdigit(tmp) && tmp != '-');    if (tmp == '-')    {        sgn = 0;        tmp = getchar();    }    do res = (res << 3) + (res << 1) + tmp - '0';    while (isdigit(tmp = getchar()));    return sgn ? res : -res;}inline bool cmp(const LeftList *a,                const LeftList *b){return a -> key > b -> key;}//預設為小根,這裡重載比較為大根。LeftList *Merge(LeftList *a, LeftList *b){    if (!a) return b;    if (!b) return a;//待合并的兩棵子樹中,若其中一棵為空白,//則直接返回另一棵樹。    if (cmp(b, a)) std::swap(a, b);//為了方便操作,讓根值較大(大根樹)//或較小(小根樹)的樹作為合并後的根。    a -> rc = Merge(a -> rc, b);    if (!(a -> lc) || a -> rc &&        a -> rc -> dist > a -> lc -> dist)        std::swap(a -> lc, a -> rc);//調整左右子樹的位置使其滿足左偏樹的性質。//(左子樹的距離不小於右子樹的距離即左偏的性質。)    if (!(a -> rc)) a -> dist = 0;    else a -> dist = a -> rc -> dist + 1;//更新合并後的樹的距離。    return a;}inline void Del(LeftList *&a) //這裡引用符號“&”不能省。{    a = Merge(a -> lc, a -> rc);    return;}int main(){    freopen("Financial_Fraud.in", "r", stdin);    freopen("Financial_Fraud.out", "w", stdout);    int n;    while (n = getint())    {        int top = 0;        for (int i = 0; i < n; ++i)        {            tr[++top] = new LeftList(a[i] = getint());            sz[top] = 1; L[top] = R[top] = i;//用L,R指標記錄當前左偏樹所代表的區間。            while (top > 1 && tr[top - 1] -> key                   > tr[top] -> key)            {                tr[top - 1] = Merge(tr[top - 1], tr[top]);                sz[top - 1] += sz[top];                R[top - 1] = R[top];                for (--top; sz[top] > ((R[top] - L[top])                     >> 1) + 1; --sz[top])                    Del(tr[top]);//使得合并後的左偏樹的根節點(即最大值)//不超過該區間的中位元,即讓左偏樹中//總節點數不超過該區間中總結點數的一半。            }        }        long long ans = 0;        for (int i = 1; i < top + 1; ++i)        for (int j = L[i]; j < R[i] + 1; ++j)            ans += abs(a[j] - tr[i] -> key);        printf("%lld\n", ans);    }    return 0;}#undef abs

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.