zoukankan      html  css  js  c++  java
  • UVA1406

    UVA1406 - A Sequence of Numbers(树状数组)

    题目链接

    题目大意:
    给定N个数字。给两种操作:C x: 把这N个数字都加上x。

    Q x:查询这N个数里面有多少个数字和2^x取且大于0.最后把每一个查询的结果求和作为答案。

    解题思路:
    查询与2^x取且为1,那么就意味这那个符合要求的数的第x位要是1。
    可是这里还有所有加上x的操作,能够用一个变量来记录所有C操作的x的和。有这个加数的话,第x位为1的可能能够通过低位进位得到,所以这里开16个树状数组,第i个树状数组存放的是每一个数从低位開始。连续的i位的值。比如7:第0个树状数组就加上1, 第1个树状数组就加上3, 第2个树状数组就加上7...
    接下来要分情况讨论:首先假设加数是1XXX 那么 1) 1xxx + 0xxx = 1xxx这是符合条件的。而1xxx的范围【1000,1111】 。 2) 1xxx + 1xxx = 11xxx 这是符合条件的,11xxx的范围【11000,11111】。

    其次假设是 0xxx。也是分两种情况考虑,同理得到范围【1000,1111】.得到了最后符合条件的数,通过减去已知的加数。就能够求出符合查询要求的范围。

    在通过树状数组统计一下这个范围内的数有多少个存在。
    注意:推断某个位是否位1要用&,不要单纯的推断大小。

    还有每一个加数在相应每次查询的时候记得要取模上2^(x + 1).由于仅仅有后面的x位是须要用的。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    const int M = 7e4;
    const int N = 20;
    
    #define lowbit(x) ((x)&(-x))
    typedef long long ll;
    
    int n;
    int t[N], C[N][M];
    
    void add (int k, int x, int v) {
    
        while (x < M) {
    
            C[k][x] += v;
            x += lowbit(x);
        }
    }
    
    ll sum (int k, int x) {
    
        int ret = 0;
        while(x > 0) {
    
            ret += C[k][x];
            x -= lowbit(x);
        }
        return ret;
    }
    
    void init () {
    
        t[0] = 1;
        for (int i = 1; i < N; i++)
            t[i] = t[i - 1] * 2;
    }
    
    void handle (int num) {
    
        for (int i = N - 1; i >= 0; i--) {
    
            add(i, num + 1, 1);
            if (num >= t[i])
                num -= t[i];
        }
    }
    
    ll solve () {
    
        ll ans = 0;
        int addnum = 0;
        char str[10];
        int x, l, r;
    
        while (scanf ("%s", str) && str[0] != 'E') {
    
            scanf ("%d", &x);
            if (str[0] == 'C')
                addnum = (addnum + x) % t[16];
            else {            
                if (addnum & t[x]) {
    
                    l = t[x + 1] + t[x] - addnum % t[x + 1];
                    r = min(t[x + 2] - 1 - addnum % t[x + 1], t[16] - 1);
                    ans += sum (x, r + 1) - sum (x, l);
                }
    
                l = t[x] - addnum % t[x + 1];
                r = t[x + 1] - 1 - addnum % t[x + 1];
                ans += sum (x, r + 1) - sum (x, l);
    //            printf("%d %d %lld
    ", min, max, ans);
            }
        }
        return ans;
    }
    
    int main () {
    
        init();
        int cas = 0, num;
        while (scanf ("%d", &n) && n != -1) {
    
            memset (C, 0, sizeof (C));    
            for (int i = 0; i < n; i++) {
                scanf ("%d", &num);
                handle(num);
            }
            printf ("Case %d: %lld
    ", ++cas, solve());
        }
        return 0;
    }
  • 相关阅读:
    SharePoint 2013 工作流之使用Visio设计篇
    SharePoint 2013 工作流之Visual Studio开发示例篇
    Ajax
    jq判断上下滚动
    元素(绝对定位)水平垂直居中
    css3动画:animation
    自定义button上传按钮
    Json
    页面滚动到顶部
    HDU 4358 Boring counting dfs序+莫队算法
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6825799.html
Copyright © 2011-2022 走看看