【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
*/