gmoj 6829. 【2020.10.25提高组模拟】异或
\(Solution\)
异或这个东西似乎很有看头,尝试操作一波,但发现无论是建树还是从每一位上面入手似乎都不太可以。
于是最后打了个暴力走人。
正解有一个性质,就是在排序以后,只有相邻两个数异或可能成为最小值。
具体的就是,\(a<b<c\),则只有\(a\ xor\ b\)或\(b\ xor\ c\)最小,一定有其中一个小于等于\(a\ xor\ c\)。
所以我们只需要排一遍序,然后通过\(trie\)来统计答案即可。边询问边插入。
\(Code\)
#include <cstdio>
#include <algorithm>
#define N 300010
#define mo 998244353
#define db double
#define ll long long
#define mem(x, a) memset(x, a, sizeof x)
#define mpy(x, y) memcpy(x, y, sizeof y)
#define fo(x, a, b) for (int x = (a); x <= (b); x++)
#define fd(x, a, b) for (int x = (a); x >= (b); x--)
#define go(x) for (int p = tail[x], v; p; p = e[p].fr)
#define plus(x, y) x = x + y >= mo ? x + y - mo : x + y
using namespace std;
int f[N], t[N * 80], son[N * 80][2];
ll X, a[N], cf[62];
int n, ans = 0, tot = 1;
inline ll read() {
ll x = 0; int f = 0; char c = getchar();
while (c < '0' || c > '9') f = (c == '-') ? 1 : f, c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f ? -x : x;
}
void insert(ll x, int pl) {
int now_ = 1; t[1] += pl;
fd(i, 60, 1) {
int k = (x & cf[i]) != 0;
if (! son[now_][k]) son[now_][k] = ++tot;
now_ = son[now_][k], plus(t[now_], pl);
}
}
int query(ll x) {
int now_ = 1; ll s = 1;
fd(i, 60, 1) {
if (! now_ || ! t[now_]) return s;
int k = (X & cf[i]) != 0, k1 = (x & cf[i]) != 0;
if (k) now_ = son[now_][k1 ^ 1];
else plus(s, t[son[now_][k1 ^ 1]]), now_ = son[now_][k1];
}
plus(s, t[now_]);
return s;
}
int main()
{
freopen("xor.in", "r", stdin);
freopen("xor.out", "w", stdout);
n = read(), X = read();
cf[1] = 1; fo(i, 2, 60) cf[i] = cf[i - 1] << 1;
fo(i, 1, n) a[i] = read();
sort(a + 1, a + n + 1);
ans = f[1] = 1, insert(a[1], f[1]);
fo(i, 2, n) {
f[i] = query(a[i]);
plus(ans, f[i]), insert(a[i], f[i]);
}
printf("%d\n", ans);
return 0;
}
转载需注明出处。