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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章