题目大意:定义
为
的所有子序列的异或和的和。
给定
,要求
,求
有多少种可能的值。100000组数据,
题解:考虑怎么算F,发现考虑每位的贡献可以知道答案就是
乘以所有数字的或。
因此只关心所有数字的或有多少种可能。首先将n=1或者L=R判掉,发现可以用两个数字表示的都可以用恰好两个数字表示。
首先先将l和r的LCP扔掉。
然后考虑令hr表示不超过r的最大的2的次幂,r’=r-hr。
首先l~ (hr-1)和(hr+l)~ (hr+hr-1)都是可以被直接表示。
然后考虑hr~ (hr+l-1)这一段。
首先若r’+1>=l,那这一段仍然全部可以被表示。
否则hr~ (hr+r’)可以被表示,还需要考虑(hr+r’+1)~ (hr+l-1)哪些数可以被表示出来。
不难发现一定是取两个介于hr~ (hr+r’)的数字。
也就是问两个不超过r’的数字或起来,在(r’+1)~ (l-1)之间的数字有多少?
差分后变为两个不超过r’的数字或起来,能得到哪些不超过x的数字?若hr’为不超过r’的最大的2的次幂,那么发现0~ (hr+hr-1)都可以被表示出来,然后和x取min即可。
这样就做完了。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline lint inln() { lint x;scanf("%lld",&x);return x; }
inline int inn() { return int(inln()); }
const int LOG=63;//conclusion : f( {a_n} ) = 2^{n-1} \times OR_{i=1}^n a_i
inline lint h(lint x) { for(int i=LOG;i>=0;i--) if((x>>i)&1) return 1ll<<i;return 0; }
inline lint __solve(lint r,lint x) { return r?min(2*h(r),x+1):min(x+1,1ll); }
inline lint solve(lint r,lint x) { return __solve(r,x)-r-1; }
int main()
{
for(int T=inn();T;T--)
{
int n=inn();lint l=inln(),r=inln();
if(n==1||l==r) { printf("%lld\n",r-l+1);continue; }
for(int i=LOG;i>=0;i--)
{
int lp=(l>>i)&1,rp=(r>>i)&1;
if(rp==1&&lp==1) l^=1ll<<i,r^=1ll<<i;
else if(rp==1&&lp==0) break;
}
lint hr=h(r),rp=r^hr;
if(rp>=l-1) printf("%lld\n",-l+hr+hr);
else printf("%lld\n",hr-l+rp+1+hr-l+solve(rp,l-1));
}
return 0;
}