定两个整数 n 和 x。考虑序列 [1,2,3,…,n],你需要找出该序列中满足以下两个条件的子段数量: 子段包含数字 x; 子段内所有数字的按位异或(XOR)结果等于 0。 换句话说,你需要统计满足如下条件的数对 (l,r) 的数量: 1≤l≤x≤r≤n; l⊕(l+1)⊕⋯⊕r=0(其中 ⊕ 表示按位异或运算)。
这个题第一次想的是预处理一个前缀异或和,用o(1)的复杂度求区间异或和(f[r]f[l-1])但是数据量太大了,n最大为1e18,这么算复杂度为n2,肯定会超时,然后你会发现4k4k+14k+24k+3=0,也很好证明,4k相当于往左移动2,也就是向右补两个零,4k+1,4k+2,会在补的两个零上各占一个1,那么前三个数异或完就刚好等于4k+3,然后观察会发现随便一个数x,当x%4==0,前x-1个数异或和为零,所以f(x)=x,剩下的可以模拟一下,当x%4=1,f(x)=1,当x%4=2时,f(x)=x+1,当x%4=3时,f(x)=0;然后再观察会发现,当余数为0和2的时候,在1到x-1和x到n之间是不会有相等的情况的,也可以去模拟一遍,我们要找的就是1到x-1和x到n之间相等,这样的话区间异或就等于零了,所以要先统计x前后区间相同的前缀异或和,然后相乘,但是要注意的是,看着代码说一下
include<bits/stdc++.h>
using namespace std;
define mod 998244353
define int long long
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int t;cin>>t;
while(t--)
{
int n,x;cin>>n>>x;
int fn=(n+1)/4,gn=(n+3)/4;//由于数据量太大,不能预处理前缀异或,找规律发现在1到n之间有fn个余数为3,有fx个余数为1的,下面fx,gx也一样
int fx=(x)/4,gx=(x+2)/4;
fn++,fx++;//这里有一个坑就是因为左侧l是可以等于1的,那么l-1是可以取零的前0个异或和为0,0%4=0,f(0)=0,很坑,所以要多算一个,fn++,fx++;
int ans=(fx%mod)((fn-fx)%mod)+(gx%mod)((gn-gx)%mod);
cout<<ans%mod<<'\n';
}
return 0;
}
