• 【[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;
    }
    
  • 相关阅读:
    mysql支持跨表delete删除多表记录
    三种循环的流程图画法总结
    巧用svn create patch(打补丁)方案解决定制版需求
    svn branch and merge(svn切换分支和合并)详解
    visualvm
    Java -verbose[:class|gc|jni] 转 ----JAVA源码分析
    BootstrapClassloader ExtClassloader AppClassloader
    LINUX 源码+内核所有参数说明
    SDN
    人工智能之数学基础
  • 原文地址:https://www.cnblogs.com/asuldb/p/10205739.html
Copyright © 2020-2023  润新知