WhiteThe Snow in Village

[CSP-S 2022] 策略游戏

Spaceswalker-2023-10-14 18:34-71 has reading

[CSP-S 2022] 策略游戏

[CSP-S 2022] 策略游戏

题目传送门

题目分析#

本文中 A 和 B 分别代表小 L 和小 Q,而原题中的 AB 两个数组在本题中分别用 ab 表示。

矩阵这个描述就是障眼法。翻译一下题目:

A 在 a[l1r1] 中选择一个 x,然后 B 在 b[l2r2] 中选择一个 y,分数是 x×y,A 想让分数尽可能大,B 想让分数尽可能小。求分数。

肯定先思考 B 再思考 A,因为 A 会思考 B 的思考。

B 的行为就是对于 x,找到一个 b[l2r2] 中的 y,使得 x×y 最小。

具体地:

  • x0 时,B 会选择最小的 y
  • x<0 时,B 会选择最大的 y

那么 A 的行为是什么呢?还是按照正负分类讨论:

如果 A 这次想让 x0,那么 B 会选择最小的 y。如果这个 y0,那么 A 一定会选最大的 x;如果这个 y<0,那么 A 一定会选最小的非负数 x(别忘了当前制约条件 x0)。

如果 A 这次想让 x<0,那么 B 会选择最大的 y。如果这个 y0,那么 A 一定会选最大的负数 x;如果这个 y<0,那么 A 一定会选最小的 x

因此 A 的行为只有四种:选择最大的 x;最小的 x,最大的负数 x,最小的非负数 x

分别讨论 A 选择四种行为时 B 的选择,答案取最大值即可。

然后就变成了静态区间最值的板子。使用 6 个 ST 表分别存储以下信息:

  • a 的区间最大值;
  • a 的区间最小值;
  • a 的负数区间最大值;
    • 具体是把所有满足 ai0ai 全部替换为 代表这个位置不存在数,至于为何是 请读者自己思考。
  • a 的非负数区间最小值;
    • 具体是把所有满足 ai<0ai 全部替换为 + 代表这个位置不存在数。
  • b 的区间最大值;
  • b 的区间最小值。

时间复杂度 O(nlogn+q)

代码实现#

Copy
#include <bits/stdc++.h> #define rint register int #define int long long #define endl '\n' using namespace std; const int N = 1e5 + 5; const int M = 2e1 + 1; const int maxinf = 1e18; const int mininf = -1e18; int n, m, q; int maxx1[N][M], minn1[N][M]; int maxx2[N][M], minn2[N][M]; int maxx3[N][M], minn3[N][M]; int query_min(int l, int r, int *a) { int k = log2(r - l + 1); return min(a[l * M + k], a[(r - (1 << k) + 1) * M + k]); } int query_max(int l, int r, int *a) { int k = log2(r - l + 1); return max(a[l * M + k], a[(r - (1 << k) + 1) * M + k]); } // maxx1: a 的区间最大值, minn1: a 的区间最小值 // maxx2: a 的负数区间最大值, minn2: a 的非负数区间最小值。 // maxx3: b 的区间最大值, minn3: b 的区间最小值。 signed main() { cin >> n >> m >> q; for (rint i = 1; i <= n; i++) { int k; cin >> k; maxx1[i][0] = minn1[i][0] = k; maxx2[i][0] = (k < 0 ? k : mininf); minn2[i][0] = (k >= 0 ? k : maxinf); } for (rint i = 1; i <= m; i++) { int k; cin >> k; maxx3[i][0] = k; minn3[i][0] = k; } for (rint j = 1; j <= 21; j++) { for (rint i = 1; i + (1 << j) - 1 <= n; ++i) { int k = i + (1 << (j - 1)); maxx1[i][j] = max(maxx1[i][j - 1], maxx1[k][j - 1]); maxx2[i][j] = max(maxx2[i][j - 1], maxx2[k][j - 1]); minn1[i][j] = min(minn1[i][j - 1], minn1[k][j - 1]); minn2[i][j] = min(minn2[i][j - 1], minn2[k][j - 1]); } } for (rint j = 1; j <= 21; j++) { for (rint i = 1; i + (1 << j) - 1 <= m; i++) { int k = i + (1 << (j - 1)); maxx3[i][j] = max(maxx3[i][j - 1], maxx3[k][j - 1]); minn3[i][j] = min(minn3[i][j - 1], minn3[k][j - 1]); } } while (q--) { int l1, r1, l2, r2; cin >> l1 >> r1 >> l2 >> r2; int amax = query_max(l1, r1, (int *)maxx1); int amin = query_min(l1, r1, (int *)minn1); int afmx = query_max(l1, r1, (int *)maxx2); int afmn = query_min(l1, r1, (int *)minn2); int bmax = query_max(l2, r2, (int *)maxx3); int bmin = query_min(l2, r2, (int *)minn3); int ans = mininf; ans = max(ans, amax * (amax >= 0 ? bmin : bmax)); ans = max(ans, amin * (amin >= 0 ? bmin : bmax)); if (afmx != mininf) { ans = max(ans, afmx * (afmx >= 0 ? bmin : bmax)); } if (afmn != maxinf) { ans = max(ans, afmn * (afmn >= 0 ? bmin : bmax)); } cout << ans << endl; } return 0; }
posted @   南松的科技树  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
Reading Sub
?