2021杭电多校2 K I love max and multiply

题目描述

https://acm.hdu.edu.cn/showproblem.php?pid=6971

简要题意:给定两个长度为 $n$ 的序列 $A_i$ 和 $B_i$,求另一个长度为 $n$ 的序列 $C_i$,满足 $C_k=\max\lbrace A_iB_j\rbrace$,其中 $i~and~j\ge k$

$n< 2^{18}$

Solution

比较直接的想法是求 $D_k=\max_{i~and~j=k}A_iB_j$,然后倒着做一遍 $\max$

但是这个东西并不好求,所以我们还是回归到原问题 $C_k=\max_{i~and~j\ge k}A_iB_j$

我们考虑求 $E_k=\max_{k\in i~and~j}A_iB_j$,最后倒着做一遍 $\max$ 即可

这个东西显然可以直接上高维前缀和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#define maxn 400010
#define ll long long
#define INF 1000000001
#define inf 1000000000000000001
using namespace std;

const int p = 998244353;

int n, A[maxn], B[maxn], a[maxn], b[maxn];

void work() {
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;
n = m;
for (int o = 0; (1 << o) < n; ++o)
for (int S = n - 1; ~S; --S)
if (!(S >> o & 1)) {
A[S] = max(A[S], A[S | 1 << o]);
B[S] = max(B[S], B[S | 1 << o]);
a[S] = min(a[S], a[S | 1 << o]);
b[S] = min(b[S], b[S | 1 << o]);
}
ll ans = -inf, sum = 0;
for (int i = n - 1; ~i; --i) {
if (A[i] != -INF && B[i] != -INF) ans = max(ans, 1ll * A[i] * B[i]);
if (A[i] != -INF && b[i] != INF) ans = max(ans, 1ll * A[i] * b[i]);
if (a[i] != INF && B[i] != -INF) ans = max(ans, 1ll * a[i] * B[i]);
if (a[i] != INF && b[i] != INF) ans = max(ans, 1ll * a[i] * b[i]);
if (ans != -inf) sum = (sum + ans) % p;
} cout << (sum + p) % p << "\n";
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

int T; cin >> T;
while (T--) work();
return 0;
}