Description

小 Q 学习位运算时发现了异或的秘密.

小 Q 是一个热爱学习的人, 他经常去维基百科 http://en.wikipedia.org/wiki/Main_Page 学习计算机科学.

就在刚才, 小 Q 认真地学习了一系列位运算符 http://en.wikipedia.org/wiki/Bitwise_operation, 其中按位异或的运算符 xor 对他影响很大. 按位异或的运算符是双目运算符. 按位异或具有 交换律, 即 \(\ \text{xor}\ j = j\ \text{xor}\ i\).

他发现, 按位异或可以理解成被运算的数字的二进制位对应位如果相同, 则结果的该位置为 \(0\), 否则为 \(1\), 例如 \((01)_2\ \text{xor}\ (10)_2 = (11)_{2}\).

他还发现, 按位异或可以理解成数字的每个二进制位进行了不进位的加法, 例如 $(11) _2   (11) 2=(00) {2}.

于是他想到了两个关于异或的问题, 这两个问题基于一个给定的非负整数序列 \(A_1, A_2, \ldots, A_n\), 其中 \(n\) 是该序列的长度.

第一个问题是, 如果用 \(f(i, j)\) 表示 \(A_i\ \text{xor}\ A_{i+1}\ \text{xor}\ \ldots\ \text{xor}\ A_j\), 则任意的 \(1 \leq i \leq j \leq n\)\(f(i, j)\) 相加是多少.

第二个问题是, 如果用 \(g(i, j)\) 表示 \(A_i + A_{i+1} + \ldots + A_j\), 则任意的 \(1 \leq i \leq j \leq n\)\(g(i, j)\) 异或在一起是多少.

比如说, 对于序列 \(\{1, 2\}\), 所有的 \(f()\)\(\{1, 2, 1\ \text{xor}\ 2\}\), 加起来是 \(6\); 所有的 \(g()\)\(\{1, 2, 1 + 2\}\), 异或起来是 \(0\).

他觉得这两个问题都非常的有趣, 所以他找到了你, 希望你能快速解决这两个问题, 其中 第一个问题的答案可能很大, 你只需要输出它对 \(998244353\) (一个质数) 取模的值即可.

Input

第一行一个正整数 \(n\), 表示序列的长度.

第二行 \(n\) 个非负整数 \(A_1, A_2, \ldots, A_n\), 表示这个序列.

Output

两个整数, 表示两个问题的答案, 空格隔开, 其中第一个问题的答案要对 \(998244353\) 取模.

Sample Input

2
1 2

Sample Output

6 0

Data Range

100% 的数据满足:\(n \leq 10^5, A_i \leq 10^6\).

Explanation

传送门:http://blog.csdn.net/skywalkert/article/details/45401245

我是蒟蒻只会写树状数组不会做题;

我是蒟蒻连树状数组都能写错 change();

我是蒟蒻目测挂菜 QwQ

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long lli;
const int maxn = 100100;
const int modr = 998244353;

class BinaryIndexedTree
{
public:
    int dat[maxn], n;
    void change(int x)
    {
        for (; x <= n; x += ~x & (x + 1))
            dat[x] ^= 1;
        return ;
    }
    int query(int x)
    {
        int res = 0;
        for (; x >= 0; x -= ~x & (x + 1))
            res ^= dat[x];
        return res;
    }
    void init(int n)
    {
        this->n = n;
        memset(dat, 0, sizeof(dat));
        return ;
    }
} bit;

int n, arr[maxn];
int xsum[maxn]; // Sum of logic xor
lli ssum[maxn]; // Sum of arithmetic addition
lli p[maxn];

template <typename _T1, typename _T2>
void remod(_T1& a, _T2 b) {
    lli c = (lli)a + (lli)b;
    while (c > modr)
        c -= modr;
    a = c; return ;
}

template <typename _T>
inline int get_digit(_T a, int b) {
    return (a >> b) & 1;
}

int find(lli val)
{
    int l = -1, r = n;
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (p[mid] <= val) l = mid;
        else r = mid - 1;
    }
    return l;
}

int main(int argc, char** argv)
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &arr[i]);
        xsum[i] = xsum[i-1] ^ arr[i];
        ssum[i] = ssum[i-1] + arr[i];
    }
    // Subtask #1, calculate the sum of xor sums
    int res1 = 0;
    for (int k = 0; k < 30; k++) { // For each digit
        int cnt[2] = {}, tmp = 0;
        // For each item in items, calculate sums
        for (int i = 0; i <= n; i++) {
            remod(tmp, cnt[get_digit(xsum[i], k) ^ 1]);
            cnt[get_digit(xsum[i], k)] += 1;
        }
        // Add temporary point to result
        remod(res1, (1ll << k) * tmp % modr);
    }
    // Subtask #2, calculate the xor sum of sums
    lli res2 = 0;
    for (lli k = 0; (1ll << k) <= ssum[n]; k++) { // For each digit (large!)
        int tmp = 0;
        // Get certain digits.
        for (int i = 0; i <= n; i++)
            p[i] = ssum[i] & ((1ll << (k+1)) - 1);
        sort(p, p + n + 1);
        bit.init(n);
        for (int i = 0; i <= n; i++) {
            lli cur = ssum[i] & ((1ll << (k+1)) - 1);
            bit.change(find(cur));
            tmp ^= bit.query(find(cur - (1ll << k)))
                ^  bit.query(find(cur + (1ll << k)))
                ^  bit.query(find(cur));
        }
        if (tmp)
            res2 |= 1ll << k;
    }
    // Gather information
    printf("%d %lld\n", res1, res2);
    return 0;
}