bzoj 4017 小Q的无敌异或(所有子区间异或的和 与和的异或)

来源:互联网 发布:张艺兴直播的软件 编辑:程序博客网 时间:2024/03/29 01:20

题目链接

小Q的无敌异或
长度为 n 的序列 求所有子区间的异或的和% 998244353,与所有子区间的和的异或。

分析

感谢skywalkert 提供题解
按位计算就好

AC code

#include <bits/stdc++.h>using namespace std;#define ms(x,v) (memset((x),(v),sizeof(x)))typedef long long LL;const int maxn = 1e5+10;const int MOD = 998244353;int x[maxn],n;LL sum[maxn];int bit[maxn];LL p[maxn];void add(int idx){    while (idx <maxn){        bit[idx]^=1;        idx += idx &-idx;    }}int SUM(int idx){    int ret =0;    while(idx >0){        ret ^= bit[idx];        idx -= idx & -idx;    }    return ret;}inline int IDX(LL val){    int id = upper_bound(p,p+n+1,val)-p;    if(p[id]==val)id--;    return id+1;}int main(){    ios_base::sync_with_stdio(0);    cin.tie(0);    cout.tie(0);    cin>>n;    for(int i=1 ; i<=n ; ++i){        int tmp;cin>>tmp;        x[i] = x[i-1]^tmp;        sum[i] = sum[i-1] + tmp;    }    LL ans1 =0,ans2=0;    for(int k=0 ;k < 25 ; ++k){        int cnt[2] ={0,0},s=0;        for(int i=0 ; i<=n ; ++i){            s += cnt[((x[i]>>k)&1) ^ 1];            cnt[(x[i]>>k)&1]++;        }        ans1 = (ans1 + (1LL<<k)*s % MOD) % MOD;    }    for(int k=0 ; 1LL << k <= sum[n] ; ++k){        int flag = 0;//        id.clear();//        tot=0;        for(int i=0 ; i<=n ; ++i){            LL now = sum[i] &( (1LL <<(k+1))-1);            p[i]=now;        }//        tot=0;//        for(map<LL,int>:: iterator it = id.begin() ; it!=id.end() ; ++it)//            it->second= ++tot;        sort(p,p+n+1);        ms(bit,0);        for(int i=0 ; i<=n ; ++i){            LL now = sum[i] &( (1LL <<(k+1))-1);            add(IDX(now));            flag ^= SUM(IDX(now-(1LL<<k))) ^ SUM(IDX(now + (1LL<<k))) ^ SUM(IDX(now));        }        if(flag)            ans2 |= (1LL <<k);    }    cout << ans1 << " "<< ans2<<"\n";    return 0;}
原创粉丝点击