吐槽:感觉你只要没做过这种题,基本上是死翘翘的

分析:

性质:考虑将 a从小到大排序以后子序列的最小异或和肯定是产生于相邻两个元素

因此排序之后,我们只要保证选取出来相邻两个数的异或和不小于题目给出的 即可。

考虑将 DP 插入到 Trie 中,每次相当于询问满足ajxorai>=x的f(j)之和,

这个可以直接在 Trie 上 维护子树和,然后从高位到低位计算。

code by std:

#include <bits/stdc++.h>
template <class T>
inline void read(T &x)
{
    static char ch;
    while (!isdigit(ch = getchar()));
    x = ch - '0';
    while (isdigit(ch = getchar()))
        x = x * 10 + ch - '0';
}
const int MaxN = 3e5 + 5;
const int mod = 998244353;
const int MaxLog = 59;
const int MaxNode = MaxN * (MaxLog + 1);
typedef long long s64;
int n, ans;
s64 lower;
s64 a[MaxN];
int nT = 1;
int trans[MaxNode][2], sze[MaxNode];
inline void add(int &x, const int &y)
{
    x += y;
    if (x >= mod)
        x -= mod;
}
inline void modify(s64 x, int val)
{
    int u = 1;

    add(sze[1], val);
    for (int i = MaxLog; i >= 0; --i)
    {
        int c = x >> i & 1;
        if (!trans[u][c])
            trans[u][c] = ++nT;
        u = trans[u][c];
        add(sze[u], val);
    }
}
inline int query(s64 x)
{
    int u = 1, res = 0;
    for (int i = MaxLog; u && i >= 0; --i)
    {
        int c = x >> i & 1, d = lower >> i & 1;
        if (d)
            u = trans[u][c ^ 1];
        else
        {
            add(res, sze[trans[u][c ^ 1]]);
            u = trans[u][c];
        }
    }
    add(res, sze[u]);
    return res;
}
int main()
{
    freopen("xor.in", "r", stdin);
    freopen("xor.out", "w", stdout);
    read(n), read(lower);
    for (int i = 1; i <= n; ++i)
        read(a[i]);
    std::sort(a + 1, a + n + 1);
    ans = 0;
    for (int i = 1; i <= n; ++i)
    {
        int cur = (query(a[i]) + 1) % mod;
        add(ans, cur);
        modify(a[i], cur);
    }
    std::cout << ans << std::endl;
    return 0;
}
12-27 23:48