zoukankan      html  css  js  c++  java
  • [TJOI 2017]异或和

    Description

    在加里敦中学的小明最近爱上了数学竞赛,很多数学竞赛的题都是与序列的连续和相关的。所以对于一个序列,求出它们所有的连续和来说,小明觉得十分的简单。但今天小明遇到了一个序列和的难题,这个题目不仅要求你快速的求出所有的连续和,还要快速的求出这些连续和的异或值。小明很快的就求出了所有的连续和,但是小明要考考你,在不告诉连续和的情况下,让你快速求是序列所有连续和的异或值。

    Input

    第一行输入一个n,表示这序列的数序列 第二行输入n个数字a1,a2...an代表这个序列

    0<=a1,a2,...an,0<=a1+a2...+an<=10^6

    Output

    输出这个序列所有的连续和的异或值

    Sample Input

    3

    1 2 3

    Sample Output

    0

    Hint

    【样例解释】

    序列1 2 3有6个连续和,它们分别是1 2 3 3 5 6,则1 xor 2 xor 3 xor 3 xor 5 xor 6 = 0

    【数据范围】

    对于20%的数据,1<=n<=100

    对于100%的数据,1<=n <= 10^5

    题解

    难得一道省选题看一眼就有思路的。一般这种异或都是按位一位一位做的。

    定义$sum$为前缀和,我们开两个权值树状数组,一个表示处理到第$i$位时,$sum[j]$的第$i$位为$1$,$0$~$j-1$中$sum$的$1$~$i-1$位的值域,另一个表示$sum[j]$的第$i$位为$0$的情况。

    统计答案时,有两种情况:

    1.$sum[j]$的第$i$位为$1$,由于$sum$数组是单调递增的(这是一个很重要的性质),那么以$j$为子序列右端点的子序列第$i$位为$1$的情况只有两种:

      (1)左端点第$i$位为$0$,并且$1$~$i-1$位小于右端点($j$)的$1$~$i-1$位;

      (2)左端点第$i$位为$1$,并且$1$~$i-1$位大于右端点($j$)的$1$~$i-1$位。(这里特别说明一下,因为刚才说过了$sum$单调递增,所以能够保证减出来不会出现负数)

    2.$sum[j]$的第$i$位为$0$,那么以$j$为子序列右端点的子序列第$i$位为$1$的情况也只有两种:

      (1)左端点第$i$位为$1$,并且$1$~$i-1$位小于右端点($j$)的$1$~$i-1$位;

      (2)左端点第$i$位为$0$,并且$1$~$i-1$位大于右端点($j$)的$1$~$i-1$位。

    其实就是竖式减法。

    //It is made by Awson on 2017.9.28
    #include <set>
    #include <map>
    #include <cmath>
    #include <ctime>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define sqr(x) ((x)*(x))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int N = 1e5;
    const int bit_size = 1e6;
    int st[25];
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    
    int sum[N+5], a[N+5];
    int c[bit_size+5][2];
    int n, maxn;
    
    void add(bool bit, int x) {
        for (; x <= maxn+1; x += lowbit(x)) c[x][bit]++;    
    }
    int cunt(bool bit, int x) {
        int cnt = 0;
        for (; x; x -= lowbit(x)) cnt += c[x][bit];
        return cnt;
    }
    void work() {
        st[0] = 1;
        for (int i = 1; i <= 20; i++) st[i] = st[i-1]<<1;
        read(n);
        for (int i = 1; i <= n; i++)
            read(sum[i]), sum[i] += sum[i-1];
        maxn = sum[n];
        int ans = 0;
        for (int i = 0; i <= 20; i++) {
            if (st[i] > maxn) break;
            memset(c, 0, sizeof(c));
            add(0, 1);
            int flag = 0;
            for (int j = 1; j <= n; j++) {
                int tmp = st[i]&sum[j], cnt;
                if (tmp) cnt = cunt(0, a[j]+1)+cunt(1, maxn+1)-cunt(1, a[j]+1);
                else cnt = cunt(1, a[j]+1)+cunt(0, maxn+1)-cunt(0, a[j]+1);
                if (cnt%2) flag ^= 1;
                add((bool)(tmp), a[j]+1);
                a[j] |= tmp;
            }
            ans |= st[i]*flag;
        }
        printf("%d
    ", ans);
    }
    int main() {
        work();
        return 0;
    }
  • 相关阅读:
    hdu 1998 奇数阶魔方(找规律+模拟)
    巧用百度Site App新组件为企业官网打造移动站
    POJ 1276 Cash Machine
    Unity3D中使用MiniJson解析json的例子
    设计模式读书笔记-----单例模式
    android 常用资料
    Objective-C之run loop详解
    icon 图标下载
    揭开Html 标签的面纱,忘不了的html .
    12157
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7609175.html
Copyright © 2011-2022 走看看