指數序列


【問題描述】
伊凡在紙上寫下了一個由 n 個非負整數組成的序列 a1 ,a2 ,…,an 。這個序列保證單調不降。
接着,伊凡又在紙上寫下了另一個序列 2^a1 ,2^a2 ,…,2^an 。現在他想知道,最少要在這個序列中添加多少個形式為 2^x 的數(x 為非負整數),才能使這個序列所有整數的和為 2^(v-1) ,其中 v 為某個非負整數。
【輸入格式】
第 1 行包括 1 個正整數 n(1≤n≤105 )。
第 2 行包括 n 個由空格隔開的整數a1 ,a2 ,…,an 。其中,0≤ai ≤2×10^9 ,保證 a1 ≤a2 ≤…≤an 。
【輸出格式】
輸出一行一個整數,表示最少在序列中添加數的數量。
【輸入樣例 1】
4
0 1 1 1
【輸出樣例 1】
0
【輸入樣例 2】
1
3
【輸出樣例 2】
3
【樣例解釋】
在第1個樣例中不需要添加任何數,因為2^0+2^1+2^1+2^1 =1+2+2+2=7=2^3-1。
在第2個樣例中,需要至少添加 3 個數,分別為2^0,2^1,2^2 。1+2+4+8=15=2^4-1


昨天yxx問我這道題

我的思路大概就是把它看做2進制數,把它們都加起來

它們的和在二進制下中的零(前導零不算)的個數就是答案

因為你如果算上了前導零,肯定要多加幾個數吧

現在問題就出在如何維護加法

如果直接高精度復雜度會非常大

而本蒟蒻又不會map的刪除操作

就寫了個Treap……

由於\(2^n+2^n=2^{n+1}\),所以可以把兩個數合並成這個數+1

可以遍歷Treap查找出現次數>1的數,但是得先存下來,不能直接刪除,因為會破壞樹的結構

最后將Treap中序遍歷,得出來的是一個單調的序列,每個數表示二進制下這個位置上為1

剩下的大家應該都會,就不說了

最多插入和刪除約nlogn次,Treap的插入和刪除均攤logn,時間復雜度為O(nlognlogn),和用map解決的時間復雜度一樣(用map的復雜度不是O(nlogn)因為map是用紅黑樹維護的,還要再乘一個logn),而且常數小(大家都知道STL要吸氧才快)

code :

#include <bits/stdc++.h>

using namespace std;

int cnt, root;

struct treap {
    int cnt, size, val, rnd, son[2];
}t[100010];

void upd(int x) {
    t[x].size = t[t[x].son[0]].size + t[t[x].son[1]].size + t[x].cnt;
}

void rotate(int &x, int d) {
    int tmp = t[x].son[d];
    t[x].son[d] = t[tmp].son[d ^ 1];
    t[tmp].son[d ^ 1] = x;
    upd(x); upd(tmp); x = tmp;
}

int newnode(int val) {
    cnt++;
    t[cnt].val = val;
    t[cnt].rnd = rand();
    t[cnt].cnt = 1;
    t[cnt].size = 1;
    return cnt;
}

void build() {
    root = newnode(-0x7fffffff); 
    t[root].son[1] = newnode(0x7fffffff);
    upd(root);
}

void insert(int &x, int val) {
    if(!x) {
        x = newnode(val);
        return ;
    }
    t[x].size++;
    if(t[x].val == val)t[x].cnt++;
    else {
        int d = t[x].val < val;
        insert(t[x].son[d], val);
        if(t[x].rnd > t[t[x].son[d]].rnd) rotate(x, d);
    }
}

void del(int &x, int val) {
    if(!x) return ;
    if(t[x].val == val) {
        if(t[x].cnt > 1) {
            t[x].cnt--;
            t[x].size--;
            return ;
        }
        if(!t[x].son[0] || !t[x].son[1]) {
            x = t[x].son[1] + t[x].son[0];
        } else {
            int d = t[t[x].son[0]].rnd > t[t[x].son[1]].rnd;
            rotate(x, d);
            del(x, val);
        }
    } else {
        t[x].size--;
        int d = t[x].val < val;
        del(t[x].son[d], val);
    }
}

int rank(int x, int val) {
    if(!x) return 0;
    if(t[x].val == val) return t[t[x].son[0]].size + 1;
    if(t[x].val > val) {
        return rank(t[x].son[0], val);
    } else {
        return rank(t[x].son[1], val) + t[t[x].son[0]].size + t[x].cnt;
    }
}

int kth(int x, int rnk) {
    if(!x) return 0x7fffffff;
    if(rnk <= t[t[x].son[0]].size) {
        return kth(t[x].son[0], rnk);
    } else {
        if(rnk <= t[t[x].son[0]].size + t[x].cnt) {
            return t[x].val;
        } else {
            return kth(t[x].son[1], rnk - t[x].cnt - t[t[x].son[0]].size);
        }
    }
}

int pre(int x, int val) {
    if(!x) return -0x7fffffff;
    if(t[x].val >= val) {
        return pre(t[x].son[0], val);
    } else {
        return max(pre(t[x].son[1], val), t[x].val);
    }
}

int nxt(int x, int val) {
    if(!x) return 0x7fffffff;
    if(t[x].val <= val) {
        return nxt(t[x].son[1], val);
    } else {
        return min(nxt(t[x].son[0], val), t[x].val);
    }
}

int flag = 0, change[10010], c[10010];

void order(int x) {
    if(!x) return ;
    if(t[x].cnt > 1) {
        change[++flag] = t[x].val;
        c[flag] = t[x].cnt;
        t[x].cnt = 1;
    }
    order(t[x].son[0]);
    order(t[x].son[1]);
}

void update() {
    for(int i = 1; i <= flag; i++) {
        if(c[i] % 2 == 0) {
            del(root, change[i]);
        }
        for(int j = 0; j < c[i] / 2; j++) {
            insert(root, change[i] + 1);
        }
    }
}

void order1(int x) {
    if(!x) return;
    order1(t[x].son[0]);
    c[++flag] = t[x].val;
    order1(t[x].son[1]);
}

int main() {
    int n;
    cin >> n;
    build();
    srand(time(NULL));
    for(int i = 1; i <= n; i++) {
        int data; cin >> data;
        insert(root, data); 
    }
    while(1) {
        flag = 0;
        order(root);
        if(!flag) break;
        update();
    }
    flag = -1;
    memset(c, 0, sizeof(c));
    order1(root);
    c[0] = -1;
    int ans = 0;
    for(int i = 1; i < flag; i++) {
        // cout << c[i] << endl;
        ans += c[i] - c[i - 1] - 1;
    }
    cout << ans << endl;
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM