[CSP-S 2022] 策略游戏
[CSP-S 2022] 策略游戏
题目分析
本文中 A 和 B 分别代表小 L 和小 Q,而原题中的 $A$,$B$ 两个数组在本题中分别用 $a$ 和 $b$ 表示。
矩阵这个描述就是障眼法。翻译一下题目:
A 在 $a[l_1 \cdots r_1]$ 中选择一个 $x$,然后 B 在 $b[l_2 \cdots r_2]$ 中选择一个 $y$,分数是 $x \times y$,A 想让分数尽可能大,B 想让分数尽可能小。求分数。
肯定先思考 B 再思考 A,因为 A 会思考 B 的思考。
B 的行为就是对于 $x$,找到一个 $b[l_2 \cdots r_2]$ 中的 $y$,使得 $x \times y$ 最小。
具体地:
- $x \ge 0$ 时,B 会选择最小的 $y$;
- $x < 0$ 时,B 会选择最大的 $y$。
那么 A 的行为是什么呢?还是按照正负分类讨论:
如果 A 这次想让 $x \ge 0$,那么 B 会选择最小的 $y$。如果这个 $y \ge 0$,那么 A 一定会选最大的 $x$;如果这个 $y < 0$,那么 A 一定会选最小的非负数 $x$(别忘了当前制约条件 $x \ge 0$)。
如果 A 这次想让 $x < 0$,那么 B 会选择最大的 $y$。如果这个 $y \ge 0$,那么 A 一定会选最大的负数 $x$;如果这个 $y <0$,那么 A 一定会选最小的 $x$。
因此 A 的行为只有四种:选择最大的 $x$;最小的 $x$,最大的负数 $x$,最小的非负数 $x$。
分别讨论 A 选择四种行为时 B 的选择,答案取最大值即可。
然后就变成了静态区间最值的板子。使用 6 个 ST 表分别存储以下信息:
- $a$ 的区间最大值;
- $a$ 的区间最小值;
- $a$ 的负数区间最大值;
- 具体是把所有满足 $a_i \ge 0$ 的 $a_i$ 全部替换为 $-\infty$ 代表这个位置不存在数,至于为何是 $-\infty$ 请读者自己思考。
- $a$ 的非负数区间最小值;
- 具体是把所有满足 $a_i < 0$ 的 $a_i$ 全部替换为 $+\infty$ 代表这个位置不存在数。
- $b$ 的区间最大值;
- $b$ 的区间最小值。
时间复杂度 $\mathcal{O}(n\log n + q)$。
代码实现
#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;
}

浙公网安备 33010602011771号