题目描述
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$ 即可
这个东西显然可以直接上高维前缀和
| 12
 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;
 }
 
 
 |