【bzoj4017】小Q的无敌异或 树状数组

来源:互联网 发布:编程用mac air还是pro 编辑:程序博客网 时间:2024/04/28 17:27
按位考虑
第一个问题,一堆0和1,求所有区间的异或的和
从前往后枚举,记录当前有多少个0,多少个1,随便一算就可以
第二个问题,一堆0和1,求所有区间的和的异或
所有大于第i位的部分我们都可以省略,于是等价于把每个数%2^(i+1)

从前往后枚举,如果两个数的差模意义下大于等于2^i,则第i位为1,于是写一个权值线段树或者离散化+树状数组即可,酸爽

虽然看上去挺简单,但还是调了很久。


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<iostream>#define maxn 100010#define mod 998244353using namespace std;long long sum[maxn],a[maxn],b[maxn],t[maxn];long long ans1,ans2;int c[maxn];int n;int lowbit(int x){return x&(-x);}void add(int i,int x){i++;if (!i) return;for (;i<=n+1;i+=lowbit(i)) c[i]^=x;}int query(int i){int ans=0;i++;for (;i;i-=lowbit(i)) ans^=c[i];return ans;}void calc1(int t){int sum=1,now=0;long long ans=0;for (int i=1;i<=n;i++){int x=((a[i]>>t)&1);now^=x;if (now==1) ans+=sum; else ans+=i-sum,sum++;}ans1=(ans1+ans*(1ll<<t)%mod)%mod;}int Query(long long x){int l=0,r=n,ans=-1;while (l<=r){int mid=(l+r)/2;if (t[mid]<=x) ans=mid,l=mid+1; else r=mid-1;}return ans;}void calc2(long long p){memset(c,0,sizeof(c));t[0]=0;for (int i=1;i<=n;i++) t[i]=(t[i-1]+a[i])%(1ll<<(p+1)),b[i]=t[i];sort(t,t+n+1);int ans=0;for (int i=0;i<=n;i++){add(Query(b[i]),1);ans^=(query(Query(b[i]-(1ll<<p)))^query(Query(b[i]))^query(Query(b[i]+(1ll<<p))));}if (ans) ans2|=(1ll<<p);}int main(){scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%lld",&a[i]);for (int i=0;i<=20;i++) calc1(i);for (int i=0;i<=40;i++) calc2(i);printf("%lld %lld\n",ans1,ans2);return 0;}


0 0
原创粉丝点击