【XSY3313】异或和(xorsum)(结论)

先上一个结论。

  • 一个长度为 \(n\)\(01\) 序列,其每个子序列的异或和的和为 \([序列中包含 1]2^{n-1}\)

证明:考虑若不存在 \(1\),则显然。否则若存在 \(1\),随便选一个 \(1\) 出来,不失一般性地设为第 \(1\) 位,然后考虑第 \(2\sim n\) 位的某个子序列的异或和 \(s\),第 \(1\) 位的 \(1\) 有且仅有一种选取方式使得 \(s\) 变为 \(1\)。故整个序列每个子序列的异或和的和就是第 \(2\sim n\) 位的子序列个数 \(2^{n-1}\)

那么按位考虑之后,\(f(a_1,a_2,\cdots,a_n)=(a_1|a_2|\cdots|a_n)\times 2^{n-1}\)。于是题目相当于询问从 \([l,r]\) 中选 \(n\) 个数或起来能得到多少种不同的结果。

再来一个结论。

  • \(n>2\)\(n=2\) 没有区别。

证明:

首先 \(n=2\) 时得到的结果一定被 \(n>2\) 时得到的结果包含,于是我们只需考虑任意一种 \(n>2\) 的结果都能被构造成两个数 \(a,b\in[l,r]\) 的或。

\(l,r\) 最高不同位为 \(h\)\(mid=2^{h}\),那么我们把 \([l,r]\) 分成 \([l,mid-1]\)(它们第 \(h\) 位都为 \(0\))和 \([mid,r]\)(它们第 \(h\) 位都为 \(1\)),考虑 \(n>2\) 时的选取情况:

  • 若选了 \([l,mid-1]\) 中的某个数,那么 \(a_1|a_2|\cdots|a_n\) 的第 \(0\sim h-1\) 位所组成的数 \(x\) 一定大于等于 \(l\),那么就一定有 \(x\in [l,mid-1]\),于是先令 \(a\gets x\),然后再视 \(a_1|a_2|\cdots|a_n\)\(h\) 位是否为 \(1\) 来考虑 \(b\gets mid\)\(b\) 不选。
  • 若没有选 \([l,mid-1]\) 中的任意一个数,即只选了 \([mid,r]\) 中的数。那么设 \(r\) 除了第 \(h\) 位以外的最高位为第 \(h'\) 位(\(r\) 的次高位),那么 \(a_1|a_2|\cdots|a_n\in [mid,mid+2^{h'+1})\),设 \(a_1|a_2|\cdots|a_n\)\(0\sim h'-1\) 位所组成的数为 \(x\),那么先令 \(a\gets mid+x\),然后再视 \(a_1|a_2|\cdots|a_n\)\(h'\) 位是否为 \(1\) 来考虑 \(b\gets mid+2^{h'}\)\(b\) 不选。

证毕。

证明的过程同时也得到了 \(a|b\) 的取值范围,于是分类讨论一下即可。

#include<bits/stdc++.h>

#define ll long long

using namespace std;

inline ll read()
{
	ll x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

int T,n;

inline ll lowbit(ll x)
{
	return x&-x;
}

int main()
{
	T=read();
	while(T--)
	{
		n=read();
		ll l=read(),r=read();
		if(n==1)
		{
			printf("%lld\n",r-l+1);
			continue;
		}
		if(l==r)
		{
			puts("1");
			continue;
		}
		ll y=l^r;
		int hb;
		for(hb=63;hb>=0;hb--)
			if((y>>hb)&1) break;
		ll z=(1ll<<(ll)(hb+1))-1;
		l&=z,r&=z;
		ll mid=(1ll<<(ll)hb);
		ll ans=(mid-l)<<1ll;
		r^=mid;
		int hbb=hb;
		for(;hbb>=0;hbb--)
			if((r>>hbb)&1ll) break;
		ll x=(1ll<<(ll)(hbb+1))-1;
		ans+=min(x,l-1)+1;
		printf("%lld\n",ans);
	}
	return 0;
}
/*
3
3 3 4
2 10 11
3 1 3
*/
/*
1
5 7 33
*/
posted @ 2022-10-30 11:01  ez_lcw  阅读(142)  评论(0编辑  收藏  举报