那么可以把
A
A
A排序后,设
f
i
f_i
fi为选到第
i
i
i个数且选了第
i
i
i个数的方案数,则
f
i
=
1
+
∑
A
i
⨁
A
j
≥
X
f
j
f_i=1+sum_{A_iigoplus A_jgeq X}f_j
fi=1+∑Ai⨁Aj≥Xfj,然而这样复杂度显然过不去。
考虑用数据结构优化
A
i
⨁
A
j
≥
X
A_iigoplus A_jgeq X
Ai⨁Aj≥X的判断,可以把每个
f
i
f_i
fi挂在线段树上,这里注意线段树的区间必须是
[
0
,
2
k
)
[0,2^k)
[0,2k),这样左右儿子可以分别对应某一位的
0
/
1
0/1
0/1,
插入就直接插入到对应的位置,
查询的话,每到一位上,如果
X
X
X的这一位为
1
1
1,那异或后是
0
0
0的子树上就都不满足,直接递归另一边;如果
X
X
X的这一位为
0
0
0,那异或后是
1
1
1的子树上就都满足,可以直接加上,也只用递归另一边。
代码
#include<cstdio>#include<cstring>#include<algorithm>usingnamespace std;#define ll long long#define N 300010#define md 998244353
ll X, a[N], F[N];int len =1;struct{
ll s =0;int l =0, r =0;}f[N *60];
ll find(int v, ll t, ll x, ll s){if(s >= X)return f[v].s;
ll sum =0;if(f[v].l &&((X & t)==0||(x & t)!=0))(sum +=find(f[v].l, t /2, x, s +((x & t)^0)))%= md;if(f[v].r &&((X & t)==0||((x & t)^ t)!=0))(sum +=find(f[v].r, t /2, x, s +((x & t)^ t)))%= md;return sum;}voidadd(int v, ll t, ll x, ll c){if(t ==0)(f[v].s += c)%= md;else{if(x & t){if(!f[v].r) f[v].r =++len;add(f[v].r, t /2, x, c);}else{if(!f[v].l) f[v].l =++len;add(f[v].l, t /2, x, c);}
f[v].s =0;if(f[v].l)(f[v].s += f[f[v].l].s)%= md;if(f[v].r)(f[v].s += f[f[v].r].s)%= md;}}intmain(){int n, i;scanf("%d%lld",&n,&X);for(i =1; i <= n; i++)scanf("%lld",&a[i]);sort(a +1, a + n +1);
ll ans =0;for(i =1; i <= n; i++){
F[i]=find(1,(1ll<<59), a[i],0)+1;add(1,(1ll<<59), a[i], F[i]);(ans += F[i])%= md;}printf("%lld
", ans);return0;}