题解:AT_abc291_g [ABC291G] OR Sum

CleverLiu

2024-11-15 22:05:56

Solution

解析

这个问题可以用卷积法来解决。

由于 A 经过 N 次运算成为原始状态,因此只需考虑 j 次运算使得 0\leq j\leq N-1 经过 j 次运算后,值 \displaystyle\sum_{i=0}^{N-1} (A_i|B_i) 由原来的给定序列 AB(运算前)表示为 \displaystyle\sum_{i=0}^{N-1} (A_{(i+j)\% N}|B_i),因此只需找出 0\leq j\leq N-1 内的最大值即可。

现在,我们来计算 0\leq j\leq N-1 的最大值。在约束条件下,0\leq A_i,B_i\leq 31,但逻辑和可以按位计算(因为它不会导致进位),所以只需考虑 0\leq A_i,B_i\leq 1;然后,我们可以独立考虑 2^0 s、 2^1 s、 2^2 s、 2^3 s 和 2^4 s 的位置。也就是说,值等于

\displaystyle\sum_{i=0}^{N-1} (A_{(i+j)\% N}|B_i) =\displaystyle\sum_{k=0}^{4}2^k\cdot\left(\displaystyle\sum_{i=0}^{N-1} (A_{(i+j)\% N,k}|B_{i,k})\right),

其中 A_{i,k}B_{i,k}A_iB_ik 个最小有效位。

对于 a=(a_0,a_1,\ldots,a_{N-1})b=(b_0,b_1,\ldots,b_{N-1}) 来说对于 (0\leq a_i,b_i\leq 1),我们如何用卷积法求得 \displaystyle\sum_{i=0}^{N-1} (a_{(i+j)\% N}|b_{i})
首先,(为了求出作为卷积的这对索引的和,)设 a'=(a'_{0},a'_{1},\ldots, a'_{2N-1})=(a_{0},a_{1},\ldots,a_{N-1},a_{0},a_{1},\ldots,a_{N-1} ) 是两份 a 的并集,b'=(b'_{0},b'_{1},\ldots, b'_{N-1})=(b_{N-1},b_{N-2},\ldots,b_{0})b 的反向,c'=a'*b'=(c'_0,c'_1,\ldots, c'_{3N-1}) 是它们的卷积;那么

c'_{N-1+j}=\displaystyle\sum_{i=0}^{N-1} a'_{i+j}\cdot b'_{N-1-i}=\displaystyle\sum_{i=0}^{N-1} a_{(i+j)\% N}\cdot b_i .

这里,对于 0\leq x,y\leq 1,如果 x=y=1x\cdot y,则 x\cdot y=1x=y=1,否则 x\cdot y=0x=y=1,所以 x\cdot y=x\& yx\cdot y=x\& y(其中 \& 为逻辑积(AND 运算))。此外,\overline{(x|y)}=\bar{x}\&\bar{y} 成立,其中 \bar{x}x 的否定,所以 \bar{a'}=(\bar{a}'_{0},\bar{a}'_{1},\ldots, \bar{a}'_{2N-1})\bar{b'}=(\bar{b}'_{0},\bar{b}'_{1},\ldots, \bar{b}'_{N-1}) 的卷积得

(\bar{a'}*\bar{b'})_{N-1+j} =\displaystyle\sum_{i=0}^{N-1} \bar{a}_{(i+j)\% N}\cdot \bar{b}_i =\displaystyle\sum_{i=0}^{N-1} \bar{a}_{(i+j)\% N}\& \bar{b}_i =\displaystyle\sum_{i=0}^{N-1} \overline{a_{(i+j)\% N}|b_i} =\displaystyle\sum_{i=0}^{N-1} (1-(a_{(i+j)\% N}|b_i)) =N-\displaystyle\sum_{i=0}^{N-1} (a_{(i+j)\% N}|b_i).

因此,对于 0\leq j\leq N-1,我们可以将 \displaystyle\sum_{i=0}^{N-1} (a_{(i+j)\% N}|b_{i}) 计算为 \displaystyle\sum_{i=0}^{N-1} (a_{(i+j)\% N}|b_{i})=N-(\bar{a'}*\bar{b'})_{N-1+j},即一次卷积(时间复杂度为 O(N\log N))。

剩下的工作就是计算每个比特的这个值,得到 \displaystyle\sum_{i=0}^{N-1} (A_{(i+j)\% N}|B_i),并选择其中的最大值。在这里,总时间复杂度为 O(N\log N\log M))(其中 M=\max(a_0,a_1,\ldots,a_{N-1},b_0,b_1,\ldots,b_{N-1})),已经足够快了。

代码

#include <bits/stdc++.h>
#include <atcoder/all>
using namespace std;
using namespace atcoder;
int main() {
    int n;
    cin >> n;
    vector <int> a(n), b(n), c(n), aa(n << 1), bb(n), cc;
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 0; i < n; i++) cin >> b[i];

    for (int j = 0; j < 5; j++) {
        for (int i = 0; i < n; i++) {
            aa[i] = (~a[i] >> j) & 1;
            aa[n + i] = aa[i];
            bb[n - i - 1] = (~b[i] >> j) & 1;
        }
        cc = convolution (aa, bb);
        for (int i = 0; i < n; i++) {
            c[i] += (n - cc[n + i - 1]) << j;
        }
    }

    int ans = 0;
    for (int i = 0; i < n; i++) ans = max(ans, c[i]);
    cout << ans << endl;
    return 0;
}

译自英文官方题解,并对卷积法做相关补充。