zoukankan      html  css  js  c++  java
  • 指数序列

    【问题描述】
    伊凡在纸上写下了一个由 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个样例中不需要添加任何数,因为20+21+21+21 =1+2+2+2=7=2^3-1。
    在第2个样例中,需要至少添加 3 个数,分别为20,21,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;
    }
    
  • 相关阅读:
    什么是前后端分离?
    Ubuntu修改时区和更新时间
    待学
    Pycharm默认输入状态是insert状态,选中文字无法直接输入替换或删除
    使用jsonify返回json数据
    Linux
    Linux
    Linux
    JavaScript
    JavaScript
  • 原文地址:https://www.cnblogs.com/iycc/p/10369489.html
Copyright © 2011-2022 走看看