bzoj4017 小Q的无敌异或 数学

来源:互联网 发布:mysql去空格函数 编辑:程序博客网 时间:2024/06/02 15:33

        一般和异或相关的求和都是一位一位来的。这题也一样。

       首先看第一问。令sum[i]=a[1]^a[2]^...^a[i],那么xor(l,r)=sum[l-1]^sum[r],考虑每一位对答案带来的影响。假设现在考虑二进制第k位(从低到高)对答案的影响。

       对于sum[x],它的第k位对答案的影响为2^k*t,其中t为1..x-1中sum[]值二进制第k位与sum[x]不同的数的个数。那么在k确定的情况下O(N)扫一遍即可。时间复杂度O(Nmax{log A})。

       然后看第二问,继续考虑第k位对答案的影响。令sum[i]=sum[i-1]+a[i],则sum(l,r)=sum[r]-sum[l-1],那么第k位对答案有影响当且仅当存在奇数对(x,y),满足x<=y且sum[x-1]和sum[y]的第k为不同。考虑在mod (2^(k+1))的意义下,任意;两个sum[l]和sum[r],它们的第k为不同,当且仅当sum[r]-sum[l]>=2^k,或者sum[r]+2^k+1-sum[l]>=2^k。因此只需要考虑有多少对(x,y),x<=y,满足sum[y]-sum[x-1]>=2^k 或者sum[y]<sum[x-1] 且 sum[x-1]-sum[y]<=2^k即可,用树状数组维护即可。时间复杂度O(NlogNlog sum|A|)。

AC代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define ll long long#define N 100005#define mod 998244353using namespace std;int n,cnt,a[N],c[N]; ll m,sum[N],num[N],hash[N],p[N];void ins(int x,int t){for (; x<=cnt; x+=x&-x) c[x]^=t;}int getxor(int x){int t=0; for (; x; x-=x&-x) t^=c[x];return t;}int find(ll x){if (x<0) return 0; int l=1,r=cnt+1;while (l+1<r){int mid=(l+r)>>1;if (hash[mid]<=x) l=mid; else r=mid;}return l;}int main(){scanf("%d",&n); int i; ll k,ans=0;for (i=1; i<=n; i++){scanf("%d",&a[i]); sum[i]=sum[i-1]^a[i];m=max(m,sum[i]);}for (k=1; k<=m; k<<=1){c[0]=1; c[1]=0;for (i=1; i<=n; i++){int tmp=(sum[i]&k)?1:0;ans=(ans+k*c[tmp^1]%mod)%mod; c[tmp]++;}}printf("%lld ",ans); ans=0;for (i=1; i<=n; i++) sum[i]=sum[i-1]+a[i];for (k=1; k<=sum[n]; k<<=1){for (i=0; i<=n; i++) num[i]=p[i]=sum[i]&((k<<1)-1);sort(num,num+n+1); hash[cnt=1]=num[0];memset(c,0,sizeof(c));for (i=1; i<=n; i++)if (num[i]!=num[i-1]) hash[++cnt]=num[i];int tmp=0;for (i=0; i<=n; i++){tmp^=getxor(find(p[i]-k))^getxor(find(p[i]))^getxor(find(p[i]+k));ins(find(p[i]),1);}if (tmp) ans|=k;}printf("%lld\n",ans);return 0;}


by lych

2016.2.27

1 0
原创粉丝点击