zoukankan      html  css  js  c++  java
  • codeforces 1041 E.Vasya and Good Sequences(暴力?)

    E. Vasya and Good Sequences
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Vasya has a sequence $$$a$$$ consisting of $$$n$$$ integers $$$a_1, a_2, dots, a_n$$$. Vasya may pefrom the following operation: choose some number from the sequence and swap any pair of bits in its binary representation. For example, Vasya can transform number $$$6$$$ $$$(dots 00000000110_2)$$$ into $$$3$$$ $$$(dots 00000000011_2)$$$, $$$12$$$ $$$(dots 000000001100_2)$$$, $$$1026$$$ $$$(dots 10000000010_2)$$$ and many others. Vasya can use this operation any (possibly zero) number of times on any number from the sequence.

    Vasya names a sequence as good one, if, using operation mentioned above, he can obtain the sequence with bitwise exclusive or of all elements equal to $$$0$$$.

    For the given sequence $$$a_1, a_2, ldots, a_n$$$ Vasya'd like to calculate number of integer pairs $$$(l, r)$$$ such that $$$1 le l le r le n$$$ and sequence $$$a_l, a_{l + 1}, dots, a_r$$$ is good.

    Input

    The first line contains a single integer $$$n$$$ ($$$1 le n le 3 cdot 10^5$$$) — length of the sequence.

    The second line contains $$$n$$$ integers $$$a_1, a_2, dots, a_n$$$ ($$$1 le a_i le 10^{18}$$$) — the sequence $$$a$$$.

    Output

    Print one integer — the number of pairs $$$(l, r)$$$ such that $$$1 le l le r le n$$$ and the sequence $$$a_l, a_{l + 1}, dots, a_r$$$ is good.

    Examples
    Input
    3
    6 7 14
    Output
    2
    Input
    4
    1 2 1 16
    Output
    4
    Note

    In the first example pairs $$$(2, 3)$$$ and $$$(1, 3)$$$ are valid. Pair $$$(2, 3)$$$ is valid since $$$a_2 = 7 ightarrow 11$$$, $$$a_3 = 14 ightarrow 11$$$ and $$$11 oplus 11 = 0$$$, where $$$oplus$$$ — bitwise exclusive or. Pair $$$(1, 3)$$$ is valid since $$$a_1 = 6 ightarrow 3$$$, $$$a_2 = 7 ightarrow 13$$$, $$$a_3 = 14 ightarrow 14$$$ and $$$3 oplus 13 oplus 14 = 0$$$.

    In the second example pairs $$$(1, 2)$$$, $$$(2, 3)$$$, $$$(3, 4)$$$ and $$$(1, 4)$$$ are valid.

    题意
    对于任何一个$$$a_i$$$,可以将其表示为$$$2$$$进制并任意更改它里面1的位置。对于区间[l,r],如果对其中一些数执行任意次这样的操作,从而使得区间的异或和为0,就称这段区间是good。给$$$n$$$个数,$$$1le a_ile 10^{18}$$$,求有多少个子区间是good。
    分析
    异或和只与二进制中$$$1$$$的个数有关,所以用$$$b_i$$$记录$$$(a_i)_2$$$中的$$$1$$$的个数,形成一个新的数组$$$b[n]$$$,之后就不再考虑数组$$$a[n]$$$了。
    为了方便叙述,用$$$xoplus y$$$表示对$$$x,y$$$进行任意调整后,可能的异或值的集合。容易发现两个数的情况($$$xlt y$$$),结果是一个公差为2的等差序列: $$$$$$ egin{align} xoplus y={|y-x|, |y-x|+2, ..., x+y } end{align} $$$$$$ 三个数的情况($$$xlt ylt z$$$),结果也是公差为2的等差序列: $$$$$$ egin{align} xoplus yoplus z={min{|z-t|, tin xoplus y}, ..., x+y+z } end{align} $$$$$$ 分析可以发现,区间可能的异或值的范围,上限是区间和,下限是一个小于最大元素的数,要判断异或值能否为0,最暴力的方法,就是把$$$min{...}$$$里面遍历一遍,看0是不是在其中,而这需要很大的代价。
    有一个更好的解决办法,注意到上限是一个很容易维护的值,而下限一定小于区间的最大元素,假设$$$[l,r]$$$内最大和第二大的数分别为$$$b_i, b_j$$$,把$$$b_i$$$单独拿出来,剩下的数形成新的区间,那么新区间的上限就是的新的区间和,下限就是一个小于$$$b_j$$$的数,所以下限一定小于$$$b_i$$$。要让原区间下限为0,就转而去判断新区间对应的等差序列中有没有$$$b_i$$$,因为如果有,就可以抵消掉,从而原区间的下限就是0。具体的来说,$$$b_i$$$要在其中,要满足两个条件:
    【1】上限大于或等于$$$b_i$$$;
    【2】$$$b_i$$$与上限同奇偶;
    这样一来,通过上限就能确定区间是否为good,完全避免了对下限的考虑了。但是单独把$$$b_i$$$提出来还是很麻烦,不如把条件转化为对整个区间的限制:
    【1】区间和大于或等于最大元素的两倍;
    【2】区间和是偶数;
    还有一个性质,$$$b_i$$$的范围是1~63,也就意味着,只要区间的长度不小于64,区间和≥63+$$$b_i$$$≥$$$2b_i$$$,就一定满足条件【1】,所以只用考虑所有长度小于64的区间,于是问题的规模就缩小到了64n,就变成了一个使劲码就能做出来的题了。
    一种比较好的写法是,先算求和为偶数的区间的总个数,再遍历所有长度小于64且和为偶数的区间,从总个数中去掉不满足条件的,剩下的个数就是答案。
    总结
    分析问题眼光还是不够敏锐啊。结合了官方题解+拜读大佬的代码,整理出这样一个还算完整的思路,花了一晚上。什么时候才能在比赛中,独立做出这样的题呢。
    代码
    #include<stdio.h>
    typedef long long LL;
    int cnt(LL x) {
        int res = 0;
        while (x)res += x & 1, x >>=1;
        return res;
    }
    int b[300005]={0},fre[300005]; 
    LL ai;
    int cnt0 = 0, cnt1 = 0;
    int main(){
        int n;
        scanf("%d", &n);
        for(int i=1;i<=n;++i)    {
            scanf("%I64d", &ai); b[i] = cnt(ai); fre[i] = fre[i - 1] + b[i];
            if (fre[i] & 1)cnt1++;
            else cnt0++;
        }
        /*求和为偶数的区间个数:
         *
         *对于前缀和为奇数的[0,l1], [0,l2], ..., [0,lcnt1]
         * 对l1而言,它和后面的组合起来,[l1+1,l2], [l1+1,l3], ..., [l1+1,lcnt1]的和一定全都是偶数
         * l2~lcnt1也同理,共cnt1-1+cnt1-2+...1=cnt1(cnt1-1)/2个
         * 
         * 对于和为偶数的区间[0,r1], [0, r2], ..., [0,rcnt0]
         * 
         * 不仅和奇数的相同,每个区间本身也要加入计数
         * 所以共cnt0+cnt0-1+...+1=(cnt0+1)cnt0/2个
         */
        LL ans = 1LL * cnt1*(cnt1 - 1) / 2+1LL*cnt0*(cnt0+1)/2;
    
        //遍历所有以i为起点的区间
        for(int i=1;i<=n;++i)    {
            int maxn = 0,sum;
            //只检查到长度为64
            for(int j=0;j<=64&&i+j<=n;++j){
                if (maxn < b[i + j])maxn = b[i + j];
                sum = fre[i + j] - fre[i - 1];
                if ((sum & 1) == 0 && (maxn<<1) > sum)ans--;
            }
        }
        printf("%I64d", ans);
    }
  • 相关阅读:
    MySQL和B树的那些事
    记一次临时抱佛脚的性能压测经历
    zookeeper api
    zookeeper笔记
    Mysql优化系列(1)--Innodb重要参数优化
    搞懂MySQL InnoDB B+树索引
    我以为我对Mysql索引很了解,直到我遇到了阿里的面试官
    HDFS原理概念扫盲
    设计原则
    设计模式 6大则
  • 原文地址:https://www.cnblogs.com/tobyw/p/9714952.html
Copyright © 2011-2022 走看看