专栏文章
题解:P11799 【MX-X9-T3】『GROI-R3』Powerless
P11799题解参与者 3已保存评论 2
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @mio18yk3
- 此快照首次捕获于
- 2025/12/02 11:42 3 个月前
- 此快照最后确认于
- 2025/12/02 11:42 3 个月前
提供一种好想好写的做法!
要拆掉 。
-
如果 ,那么 , 就可以去掉。记录数 的出现次数 ,对于同一类,两两之间的贡献是 。
-
如果 ,发现 和 的贡献是相等的,可以在取最小值的位置计算贡献,最后 即可。不妨设 ,那么贡献在 处计算,这部分的贡献是 。
现在我们要计算
先考虑第一项:
记 表示 的最高有效位, 表示 在二进制下的第 位。
发现影响 和 大小的是 和 ,也就取决于两数在第 位的值。和 无关。
令 ,这意味着 ,所以能贡献的 一定满足 ,这样,,所以一定有 。
枚举 和 ,这部分的贡献可以写成
左边括号的值,相当于求 位都与 相同,第 位不同的数的个数。可以把所有 插入 01 trie,就变成求子树大小。记为 。
右边括号的值,拆位,对于第 位,所有满足 且 的 都能产生 的贡献。
考虑预处理数组 表示 中满足 的 的个数。可以用数位 dp 求出。
再考虑第二项:
这就容易多了,一样的思路,拆位,对于第 位,所有满足 的 都能产生 的贡献。利用预处理好的 数组。
加起来就是最终的答案:
,其中 是值域大小。
实现
CPP#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
#ifdef ONLINE_JUDGE
#define debug(...) 0
#else
#define debug(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#endif
constexpr int N = 2e5 + 5, mod = 998244353;
int n, m;
int a[N];
unordered_map<int, int> mp;
int tr[N * 29][2], idx;
int siz[N * 29];
void insert(int x) {
int p = 0;
for (int i = 29; i >= 0; i--) {
int v = x >> i & 1;
if (!tr[p][v]) tr[p][v] = ++idx;
p = tr[p][v];
}
siz[p]++;
}
void dfs(int u) {
if (!u) return;
for (int i = 0; i <= 1; i++) {
dfs(tr[u][i]);
siz[u] += siz[tr[u][i]];
}
}
int f[30][30][2][2]; // f[i][j][0 / 1][0 / 1] k \in [0, m] 且使得 k 第 i 位为 0/1,第 j 位为 0/1 的 k 的数量
int dp[30];
int dfs(int pos, int p1, int p2, int v1, int v2, int lim) {
if (pos == -1) return 1;
if (!lim && ~dp[pos]) return dp[pos];
int res = 0;
for (int i = 0; i <= (lim ? m >> pos & 1 : 1); i++) {
if (pos == p1 && i != v1) continue;
if (pos == p2 && i != v2) continue;
res += dfs(pos - 1, p1, p2, v1, v2, lim && (i == (m >> pos & 1)));
}
return lim ? res : dp[pos] = res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
mp[a[i]]++;
insert(a[i]);
}
sort(a + 1, a + 1 + n);
for (int i = 0; i <= 29; i++)
for (int j = 0; j <= 29; j++)
for (int v1 = 0; v1 <= 1; v1++)
for (int v2 = 0; v2 <= 1; v2++) {
memset(dp, -1, sizeof dp);
f[i][j][v1][v2] = dfs(29, i, j, v1, v2, 1);
}
for (int i = 0; i <= 1; i++)
if (tr[0][i])
dfs(tr[0][i]);
int ans = 0;
for (int i = 1; i <= n; i++) {
int x = a[i];
for (int c = 0; c <= 29; c++) {
int p = 0;
for (int j = 29; j > c; j--) p = tr[p][x >> j & 1];
int sz = siz[tr[p][!(x >> c & 1)]];
int con = 0;
for (int j = 0; j <= 29; j++)
con = (con + 1ll * (1 << j) * f[j][c][!(x >> j & 1)][x >> c & 1]) % mod;
ans = (ans + 1ll * sz * con) % mod;
}
}
ans = 1ll * ans * 2 % mod;
n = unique(a + 1, a + 1 + n) - a - 1;
for (int i = 1; i <= n; i++) {
int res = 0;
for (int j = 0; j <= 29; j++) {
int v = a[i] >> j & 1;
res = (res + 1ll * (1 << j) * f[j][j][v ^ 1][v ^ 1]) % mod;
}
ans = (ans + 1ll * mp[a[i]] * mp[a[i]] % mod * res) % mod;
}
cout << ans << "\n";
return 0;
}
相关推荐
评论
共 2 条评论,欢迎与作者交流。
正在加载评论...