CodeForces 626 DIV.2 D Present

题目

题解: 现场想到了从结果的二进制的每一位考虑,每一位都是由比它低的低位决定的,但是规律没找好。
举个例子,结果的二进制的第3位(从0位开始)上是否为1,是由0 到 2^4-1 之间的数决定,就是 0000 - 1111 之间所有数两两相加决定的,所以数组要先对2^4取余。
而相加的结果,只有在1000 到 1111 ,也就是8~15之间,才会让第3位为1,统计为1的结果若是奇数,则最终结果的第三位上就是1,否则为0
对 0 来说,和1000-1111 任意的数字相加,都会让第3位为1
对 0001 来说,和0111- 1110之间的任意数字相加,也满足条件
0010 ~ 0110-1101
...
1111 ~ 0000-0000 和 1001~1111
总的来说,考虑第3位,对任意的x(x在0~2^4-1之间), 就是看看在[2^3-x ~ 24-x]和[24-1+23-x,24-1]两个区间里有多少个数字。求区间和,可以用树状数组。
考虑第k为,对于任意的x(x在0~2^(k+1)-1 之间),统计[2k-x,2(k+1)-x] 和 [2(k+1)+2k -x-1,2^(k+1)-1] 这两个区间的和.
因为数组里数字的范围是107,任意两个数字之和最大是2*107,所以我最多考虑到第24位,2^24。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <math.h>

using namespace std;

#define MAX (int)4e5+5
#define MAX2 (1<<25)
int a[MAX];
int c[MAX2+5];
int lowbit(int x)
{
    return x&(-x);
}
void Add(int pos,int len,int x)
{
    while(pos<=len)
    {
        c[pos]+=x;
        pos+=lowbit(pos);
    }
}
int sum(int pos)
{
    if(pos<=0)
        return 0;
    int res=0;
    while(pos>0)
    {
        res+=c[pos];
        pos-=lowbit(pos);
    }
    return res;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }

    int ans=0;
    int num=1;
    for(int i=0;i<25;i++)
    {
        num<<=1;
        memset(c,0,num*sizeof(int));
        int res=0;
        for(int j=0;j<n;j++)
        {
            int x = a[j]%num;
            int xx = sum((num-1)-x+1);
            int yy = sum((num>>1)-x);

            res+= xx-yy;

            if(x>num>>1) {

                xx = sum(num);
                yy = sum(num-(x-(num>>1)));
                res+=xx-yy;
            }

            if(res&1)
            {
                res=1;
            }
            else
                res=0;

            Add(x+1,num,1);
        }

        if(res&1)
            ans |= (1<<i);
    }

    printf("%d\n",ans);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章