CF2161G Bitwise And Equals
考虑怎么写暴力。首先把所有 \(a\) 都调整成 \(X\) 的超集。设调整后的数组 \(a'_i=b_i+X\),即 \(b_i\) 为 \(a'_i\) 扣掉 \(X\) 的部分。
此时,令 \(Y\) 为 \(b_i\) 的 \(\mathrm{AND}\) 和,那么我们还需要把 \(Y\) 中的位变成 \(0\)。
一个显然的观察是,对于某一个元素操作,只会把 \(b_i\) 的一段前缀 \(0\sim w-1\) 位置成 \(0\),然后把 \(w\) 为变成 \(1\)。因为我们消除的是一段前缀,所以也一定只会操作一个数。同时一个限制是这样调整完的 \(w\) 位不能全变成 \(1\),即原来 \(w\) 位 \(=1\) 个数 \(\le n-2\)。
那么可以枚举 \(w\),此处需要保证 \(w>\mathrm{highbit}(Y)\),如果 \(=1\) 个数 \(\le n-2\),就取出第 \(w\) 位 \(=0\) 的,只考虑 \(0\sim w-1\) 位的最大 \(a_i\)。然后算一下贡献即可。
考虑怎么优化这一过程。\(Y\) 的最高位可以直接算。对于一个 \(a_i\),它调整成 \(X\) 超集,一定形如找出最高位 \(d\),使 \(X\) 的 \(d\) 位 \(=1\),\(a_i\) 的 \(d\) 位 \(=0\),然后 \(a_i\) 的 \(>d\) 位不变,\(\le d\) 位变成和 \(X\) 相同。称这样的 \(d\) 为其切割位置。
枚举切割位 \(w_2\),那么合法的 \(a_i\) 需要满足如下条件:
- \(a_i\) 的第 \(w_2\) 位 \(=0\),且对于 \(t>w_2\),如果 \(X\) 的 \(t\) 位 \(=1\),则 \(a_i\) 这一位也 \(=1\)。
而 \(a_i\) 对于答案的贡献也是好算的。如果 \(w_2\ge w\),那么说明此时所有合法的 \(a_i\) 在 \(0\sim w\) 位都被改成和 \(X\) 相同。那么只要判一下是否存在即可。如果 \(w_2<w\),那么我们只要找到考虑 \(0\sim w\) 位时最大的 \(a_i\) 即可。这些都可以直接枚举 \(w, w_2\),高维后缀和预处理出来,总复杂度是 \(O(V\log^2V)\) 的。
对于计算 \(a_i\) 变成 \(X\) 超集的部分,也可以同理枚举 \(w_2\),算法是类似的。
总复杂度 \(O(V\log^2 V)\)。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void Chkmax(int &x, int y) {
x = max(x, y);
}
const int inf = 1e9;
const int kN = 2e5 + 5, kLog = 22, kV = (1 << 20) + 5;
int n, q, andsum = (1 << 20) - 1;
int a[kN], b[kN];
int *f[kLog][kLog], *c[kLog][kLog];
ll *sum[kLog];
int *num[kLog];
template <typename T>
void FWT_Sum(int n, T *f) {
for(int i = 0; i < n; i++) {
for(int j = 0; j < (1 << n); j += (2 << i)) {
int p = j, q = j + (1 << i);
for(; p < j + (1 << i); p++, q++) {
f[p] += f[q];
}
}
}
}
ll Query(int x) {
ll res = 0;
for(int w2 = -1; w2 < 20; w2++) {
if(!((x >> w2) & 1)) continue;
res -= sum[w2 + 1][x >> w2 + 1];
res += (ll)num[w2 + 1][x >> w2 + 1] * (x & ((1 << w2 + 1) - 1));
}
int asum = andsum;
asum ^= (asum & x);
if(!asum) return res;
int wy = __lg(asum);
int tmp = (~andsum) & x;
if(tmp && __lg(tmp) > wy) return res;
int mn = inf;
for(int w1 = wy; w1 < 21; w1++) {
if((x >> w1) & 1) continue;
int t = -inf, cnt = 0;
for(int w2 = -1; w2 < 20; w2++) {
if(~w2 && !((x >> w2) & 1)) continue;
int mx = -inf;
if(w1 <= w2) {
if(c[w1][w2 + 1][x >> w2 + 1]) {
t = max(t, 0);
}
}else {
int mx = f[w1][w2 + 1][x >> w2 + 1];
int ct = c[w1][w2 + 1][x >> w2 + 1];
cnt += ct;
if(mx >= 0) {
mx &= ~((1 << w2 + 1) - 1);
t = max(t, mx ^ (mx & x));
}
}
}
if(cnt <= n - 2) {
mn = min(mn, (1 << w1) - t);
}
}
return res + mn;
}
int main() {
// freopen("1.in", "r", stdin);
// freopen("1.out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> q;
for(int i = 1; i <= n; i++) {
cin >> a[i];
andsum &= a[i];
}
for(int w2 = -1; w2 < 20; w2++) {
int len = (1 << 19 - w2);
sum[w2 + 1] = new ll [len + 5];
memset(sum[w2 + 1], 0, (len + 5) * sizeof(ll));
num[w2 + 1] = new int [len + 5];
memset(num[w2 + 1], 0, (len + 5) * sizeof(int));
}
for(int w1 = 0; w1 < 21; w1++) {
for(int w2 = -1; w2 < 20; w2++) {
if(w1 == w2) continue;
int len = (1 << 19 - w2);
if(w1 > w2) {
f[w1][w2 + 1] = new int [len + 5];
memset(f[w1][w2 + 1], 0xcf, (len + 5) * sizeof(int));
}
c[w1][w2 + 1] = new int [len + 5];
memset(c[w1][w2 + 1], 0, (len + 5) * sizeof(int));
}
}
for(int i = 1; i <= n; i++) {
for(int w2 = -1; w2 < 20; w2++) {
if(~w2 && (a[i] >> w2) & 1) continue;
int p = a[i] >> w2 + 1;
sum[w2 + 1][p] += (a[i] & ((1 << w2 + 1) - 1));
num[w2 + 1][p]++;
for(int w1 = 0; w1 < 21; w1++) {
if(w1 == w2) continue;
int v = a[i] & ((1 << w1) - 1);
if(w1 <= w2) c[w1][w2 + 1][p]++;
else if(!((a[i] >> w1) & 1)) {
Chkmax(f[w1][w2 + 1][p], v);
}else c[w1][w2 + 1][p]++;
}
}
}
for(int w2 = -1; w2 < 20; w2++) {
FWT_Sum(19 - w2, sum[w2 + 1]);
FWT_Sum(19 - w2, num[w2 + 1]);
}
for(int w1 = 0; w1 < 21; w1++) {
for(int w2 = -1; w2 < 20; w2++) {
if(w1 == w2) continue;
int wl = 19 - w2;
int *ff = f[w1][w2 + 1];
FWT_Sum(wl, c[w1][w2 + 1]);
if(w1 > w2) {
for(int i = 0; i < wl; i++) {
for(int j = 0; j < (1 << wl); j += (2 << i)) {
int p = j, q = j + (1 << i);
for(; p < j + (1 << i); p++, q++) {
ff[p] = max(ff[p], ff[q]);
}
}
}
}
}
}
while(q--) {
int x;
cin >> x;
cout << Query(x) << "\n";
}
return 0;
}
浙公网安备 33010602011771号