题目大意
给出 a 和 b 要求求一个c ck满足 ck = max(ai * bj} 且 k <= i & j 求c的总和
思路
很显然 i & j 只会生成小于等于i或j的数
还是举例说明比较清楚 :
比如k=10010 那么 i 和 j 可以选择 1xx1x的数字 所以我们可以从大到小遍历 维护所有1xx1x的最大值
即 A[10010] = max{A[10010], A[10011], A[10110], A[11010]};
为什么只求相对于10010变换一位0的数字的最大值呢 因为变换两位的在前面已经维护完了
因为A[10110] = max(A[10111], A[11110],A[10110]), 所以就不用再枚举这两个的最大值了
再举个简单点的例子
因为A[101] = max(A[101], A[111]), 所以A[100] = max(A[100],A[101],A[110])
然后要注意倒序求值 因为前面的都是根据后面的最大值来更新的
还有一点是ab可能是小于0的数 所以每次维护都要维护一个最小值一个最大值
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e6 + 10, INF = 1e9 + 7;
const LL P = 998244353;
int n;
int a[N], b[N], A[N], B[N];
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
int T;
cin >> T;
while (T -- )
{
cin >> n;
for (int i = 0; i < n; i ++ )
{
cin >> a[i];
A[i] = a[i];
}
for (int i = 0; i < n; i ++ )
{
cin >> b[i];
B[i] = b[i];
}
int m = 1;
while (m < n) m <<= 1;
for (int i = n; i <= m; i ++ )
{
A[i] = B[i] = -INF;
a[i] = b[i] = INF;
}
for (int i = n -1 ; i >= 0; i -- )
for (int j = 1; j < m; j <<= 1)
if (!(i & j))
{
A[i] = max(A[i], A[i ^ j]);
B[i] = max(B[i], B[i ^ j]);
a[i] = min(a[i], a[i ^ j]);
b[i] = min(b[i], b[i ^ j]);
}
LL ans = 0;
LL t = -(LL)INF * INF;
for (int i = n - 1; i >= 0; i -- )
{
t = max(t, (LL)A[i] * B[i]);
t = max(t, (LL)A[i] * b[i]);
t = max(t, (LL)a[i] * B[i]);
t = max(t, (LL)a[i] * b[i]);
ans = (ans + t) % P;
}
ans = (ans + P) % P;
cout << ans << endl;
}
return 0;
}