题目描述
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; }
|