zoukankan      html  css  js  c++  java
  • 【[TJOI2017]异或和】

    这道题挺神仙的,毕竟这个异或是需要进位的

    看到区间和我们很自然的就想到了前缀和

    于是处理一下前缀和答案就变成了这个样子

    [⊕sum_{i=1}^nsum_{j=1}^{i}pre_i-pre_{j-1} ]

    众所周知异或是应该按位处理的,但是这里是减法,所以还有进位需要处理

    瞬间就感觉没有办法处理了

    但是还是应该按位处理的,我们应该按位考虑这一位上最后的答案是什么

    非常显然的一点是我们在考虑某一位的时候并不需要顾忌更靠前的位置,只需要考虑后面的位置就好了

    所以我们按位考虑每一位的答案,用一个权值树状数组维护这个位置后面的数是什么

    分情况讨论一下

    1. 如果这一位上是(1),那么后面的数无论多小都无需向前面的数借位,统计一下后面的数比他小的有多少个(0),比它大的有多少个(1)就好了

    2. 这一位是(0),那么后面的统计一下后面的数比他小的有多少个(1),同时往前最靠近的那一个(1),把这一位借过来之后在考虑影响就好了

    复杂度(O(nlog^2m))

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define re register
    #define maxn 100005
    #define lowbit(x) ((x)&(-x))
    #define LL long long
    inline int read()
    {
    	char c=getchar();
    	int x=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9')
    		x=(x<<3)+(x<<1)+c-48,c=getchar();
    	return x;
    }
    int a[maxn],pre[maxn];
    int c[2][1000005];
    LL ans=0;
    int N;
    inline void add(int op,int x)
    {
    	for(re int i=x;i<=N;i+=lowbit(i))
    		c[op][i]++;
    }
    inline LL ask(int op,int x)
    {
    	LL ans_ask=0;
    	for(re int i=x;i;i-=lowbit(i))
    		ans_ask+=c[op][i];
    	return ans_ask;
    }
    int n;
    int main()
    {
    	n=read();
    	for(re int i=1;i<=n;i++) a[i]=read();
    	for(re int i=1;i<=n;i++) pre[i]=pre[i-1]+a[i];
    	LL _0=1,_1=0;
    	for(re int i=1;i<=n;i++)
    	{
    		if(pre[i]&1ll) ans+=_0,_1++;
    			else ans+=_1,_0++;
    	}
    	if(ans&1ll) ans=1;
    		else ans=0;
    	for(re LL t=1;(1<<t)<=pre[n];t++)
    	{
    		LL now=0;
    		memset(c,0,sizeof(c));
    		N=(1ll<<(t))+1;
    		add(0,1);
    		for(re int i=1;i<=n;i++)
    		{
    			int tt=pre[i]%(1ll<<t)+1;
    			if(pre[i]&(1ll<<t))
    			{
    				now+=ask(0,tt);
    				now+=ask(1,N)-ask(1,tt);
    			}
    			else
    			{
    				now+=ask(1,tt);
    				for(re int j=t+1;(1ll<<j)<=pre[i];j++)
    				if(pre[i]&(1ll<<j))
    				{
    					int p=(1ll<<j)/(1ll<<t);
    					now+=ask(((p-1)&1ll)^1ll,N)-ask(((p-1)&1ll)^1ll,tt);
    					break;
    				}
    			}
    			if(pre[i]&(1ll<<t)) add(1,tt);
    				else add(0,tt);
    		}
    		if(now&1ll) ans+=(1ll<<t);
    	}
    	std::cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    程序员必定会爱上的10款软件(转)
    用代码来细说Csrf漏洞危害以及防御
    UPX源码分析——加壳篇
    从零开始学习渗透Node.js应用程序
    自己动手python打造渗透工具集
    国内国外最好的java开发论坛及站点 [转]
    运维无小事之一次导致数据丢失的小变更
    使用python及工具包进行简单的验证码识别
    浅析企业安全中账户安全 的重要性
    全世界最顶级黑客同时沸腾在DEF CON 25,是怎样一种体验?
  • 原文地址:https://www.cnblogs.com/asuldb/p/10205739.html
Copyright © 2011-2022 走看看