[CSP-S 2022] 策略游戏
传送门
题目描述
小 L 和小 Q 在玩一个策略游戏。
有一个长度为 n n n 的数组 A A A 和一个长度为 m m m 的数组 B B B,在此基础上定义一个大小为 n × m n \times m n×m 的矩阵 C C C,满足 C i j = A i × B j C_{i j} = A_i \times B_j Cij=Ai×Bj。所有下标均从 1 1 1 开始。
游戏一共会进行 q q q 轮,在每一轮游戏中,会事先给出 4 4 4 个参数 l 1 , r 1 , l 2 , r 2 l_1, r_1, l_2, r_2 l1,r1,l2,r2,满足 1 ≤ l 1 ≤ r 1 ≤ n 1 \le l_1 \le r_1 \le n 1≤l1≤r1≤n、 1 ≤ l 2 ≤ r 2 ≤ m 1 \le l_2 \le r_2 \le m 1≤l2≤r2≤m。
游戏中,小 L 先选择一个 l 1 ∼ r 1 l_1 \sim r_1 l1∼r1 之间的下标 x x x,然后小 Q 选择一个 l 2 ∼ r 2 l_2 \sim r_2 l2∼r2 之间的下标 y y y。定义这一轮游戏中二人的得分是 C x y C_{x y} Cxy。
小 L 的目标是使得这个得分尽可能大,小 Q 的目标是使得这个得分尽可能小。同时两人都是足够聪明的玩家,每次都会采用最优的策略。
请问:按照二人的最优策略,每轮游戏的得分分别是多少?
输入格式
第一行输入三个正整数 n , m , q n, m, q n,m,q,分别表示数组 A A A,数组 B B B 的长度和游戏轮数。
第二行: n n n 个整数,表示 A i A_i Ai,分别表示数组 A A A 的元素。
第三行: m m m 个整数,表示 B i B_i Bi,分别表示数组 B B B 的元素。
接下来 q q q 行,每行四个正整数,表示这一次游戏的 l 1 , r 1 , l 2 , r 2 l_1, r_1, l_2, r_2 l1,r1,l2,r2。
输出格式
输出共 q q q 行,每行一个整数,分别表示每一轮游戏中,小 L 和小 Q 在最优策略下的得分。
样例 #1
样例输入 #1
3 2 2
0 1 -2
-3 4
1 3 1 2
2 3 2 2
样例输出 #1
0
4
样例 #2
样例输入 #2
6 4 5
3 -1 -2 1 2 0
1 2 -1 -3
1 6 1 4
1 5 1 4
1 4 1 2
2 6 3 4
2 5 2 3
样例输出 #2
0
-2
3
2
-1
提示
【样例解释 #1】
这组数据中,矩阵 C C C 如下:
[ 0 0 − 3 4 6 − 8 ] \begin{bmatrix} 0 & 0 \\ -3 & 4 \\ 6 & -8 \end{bmatrix} 0−3604−8
在第一轮游戏中,无论小 L 选取的是 x = 2 x = 2 x=2 还是 x = 3 x = 3 x=3,小 Q 都有办法选择某个 y y y 使得最终的得分为负数。因此小 L 选择 x = 1 x = 1 x=1 是最优的,因为这样得分一定为 0 0 0。
而在第二轮游戏中,由于小 L 可以选 x = 2 x = 2 x=2,小 Q 只能选 y = 2 y = 2 y=2,如此得分为 4 4 4。
【样例 #3】
见附件中的 game/game3.in
与 game/game3.ans
。
【样例 #4】
见附件中的 game/game4.in
与 game/game4.ans
。
【数据范围】
对于所有数据, 1 ≤ n , m , q ≤ 10 5 1 \le n, m, q \le {10}^5 1≤n,m,q≤105, − 10 9 ≤ A i , B i ≤ 10 9 -{10}^9 \le A_i, B_i \le {10}^9 −109≤Ai,Bi≤109。对于每轮游戏而言, 1 ≤ l 1 ≤ r 1 ≤ n 1 \le l_1 \le r_1 \le n 1≤l1≤r1≤n, 1 ≤ l 2 ≤ r 2 ≤ m 1 \le l_2 \le r_2 \le m 1≤l2≤r2≤m。
测试点编号 | n , m , q ≤ n, m, q \le n,m,q≤ | 特殊条件 |
---|---|---|
1 1 1 | 200 200 200 | 1, 2 |
2 2 2 | 200 200 200 | 1 |
3 3 3 | 200 200 200 | 2 |
4 ∼ 5 4 \sim 5 4∼5 | 200 200 200 | 无 |
6 6 6 | 1000 1000 1000 | 1, 2 |
7 ∼ 8 7 \sim 8 7∼8 | 1000 1000 1000 | 1 |
9 ∼ 10 9 \sim 10 9∼10 | 1000 1000 1000 | 2 |
11 ∼ 12 11 \sim 12 11∼12 | 1000 1000 1000 | 无 |
13 13 13 | 10 5 {10}^5 105 | 1, 2 |
14 ∼ 15 14 \sim 15 14∼15 | 10 5 {10}^5 105 | 1 |
16 ∼ 17 16 \sim 17 16∼17 | 10 5 {10}^5 105 | 2 |
18 ∼ 20 18 \sim 20 18∼20 | 10 5 {10}^5 105 | 无 |
其中,特殊性质 1 为:保证
A
i
,
B
i
>
0
A_i, B_i > 0
Ai,Bi>0。
特殊性质 2 为:保证对于每轮游戏而言,要么
l
1
=
r
1
l_1 = r_1
l1=r1,要么
l
2
=
r
2
l_2 = r_2
l2=r2。
注明
以上来自洛谷。 以上来自洛谷。 以上来自洛谷。
我劝你去学学 ST 表。
解题思路
设 A 选了 x x x,B 选了 y y y。
先想 B 的策略,再想 A。因为 A 会去对于 B 对于 A 的策略取最优策略。
具体体分析可得 B 的选择:
- x ≥ 0 x\geq 0 x≥0 时,B 会选择最小的 y y y;
- x < 0 x< 0 x<0 时,B 会选择最大的 y y y。
然后对于 B 的选择分析,可以得到 A 的选择套路:
-
x ≥ 0 x\geq 0 x≥0:
此时 B 会选择最小的 y。- 如果这个 y ≥ 0 y\geq 0 y≥0,那么 A 一定会选最大的 x x x;
- 如果这个 y < 0 y<0 y<0,那么 A 一定会选最小的非负数 x x x。
-
x < 0 x<0 x<0
此时 B 会选择最大的 y y y。- 如果这个 y ≥ 0 y\geq 0 y≥0,那么 A 一定会选最大的负数 x x x;
- 如果这个 y < 0 y<0 y<0,那么 A 一定会选最小的 x x x。
分类讨论 A 各选择方案下 B 的选择,记录对答案贡献,答案取最大值即可。
就说静态区间最值的板子。
使用 6 个 ST 表分别存储以下信息:
- a a a 的区间最大值;
- a a a 的区间最小值;
- a a a 的负数区间最大值;
- a a a 的非负数区间最小值;
- b b b 的区间最大值;
- b b b 的区间最小值。
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e5 + 5;
const int maxm = 1e5 + 5;
const int mlgn = 25;
const int mlgm = 25;
int n, m, q;
int _log[maxn], ST_A_Max[maxn][mlgn], ST_A_Min[maxn][mlgn], ST_A_F_Max[maxn][mlgn], ST_A_FF_Min[maxn][mlgn], ST_B_Max[maxm][mlgm], ST_B_Min[maxm][mlgm];
int Answer;
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> q;
for (register int i = 1, x; i <= n; ++i) {
cin >> x;
ST_A_Max[i][0] = x;
ST_A_Min[i][0] = x;
ST_A_F_Max[i][0] = (x < 0 ? x : INT_MIN);
ST_A_FF_Min[i][0] = (x >= 0 ? x : INT_MAX);
}
for (register int i = 1, x; i <= m; ++i) {
cin >> x;
ST_B_Max[i][0] = x;
ST_B_Min[i][0] = x;
}
int len = max(n, m);
for (register int i = 2; i <= len; ++i)
_log[i] = _log[i >> 1] + 1;
for (register int j = 1, p; j <= _log[n]; ++j)
for (register int i = 1; i + (1 << j) - 1 <= n; ++i) {
p = i + (1 << (j - 1));
ST_A_Max[i][j] = max(ST_A_Max[i][j - 1], ST_A_Max[p][j - 1]);
ST_A_F_Max[i][j] = max(ST_A_F_Max[i][j - 1], ST_A_F_Max[p][j - 1]);
ST_A_Min[i][j] = min(ST_A_Min[i][j - 1], ST_A_Min[p][j - 1]);
ST_A_FF_Min[i][j] = min(ST_A_FF_Min[i][j - 1], ST_A_FF_Min[p][j - 1]);
}
for (register int j = 1, p; j <= _log[m]; ++j)
for (register int i = 1; i + (1 << j) - 1 <= m; ++i) {
p = i + (1 << (j - 1));
ST_B_Max[i][j] = max(ST_B_Max[i][j - 1], ST_B_Max[p][j - 1]);
ST_B_Min[i][j] = min(ST_B_Min[i][j - 1], ST_B_Min[p][j - 1]);
}
int l_1, r_1, l_2, r_2;
int st_1, st_2, ed_1, ed_2, a_max_tmp, a_min_tmp, a_f_max_tmp, a_ff_min_tmp, b_max_tmp, b_min_tmp;
while (q--) {
cin >> l_1 >> r_1 >> l_2 >> r_2;
ed_1 = _log[r_1 - l_1 + 1];
ed_2 = _log[r_2 - l_2 + 1];
st_1 = r_1 - (1 << ed_1) + 1;
st_2 = r_2 - (1 << ed_2) + 1;
a_max_tmp = max(ST_A_Max[l_1][ed_1], ST_A_Max[st_1][ed_1]);
a_min_tmp = min(ST_A_Min[l_1][ed_1], ST_A_Min[st_1][ed_1]);
a_f_max_tmp = max(ST_A_F_Max[l_1][ed_1], ST_A_F_Max[st_1][ed_1]);
a_ff_min_tmp = min(ST_A_FF_Min[l_1][ed_1], ST_A_FF_Min[st_1][ed_1]);
b_max_tmp = max(ST_B_Max[l_2][ed_2], ST_B_Max[st_2][ed_2]);
b_min_tmp = min(ST_B_Min[l_2][ed_2], ST_B_Min[st_2][ed_2]);
Answer = max(a_min_tmp * (a_min_tmp >= 0 ? b_min_tmp : b_max_tmp), a_max_tmp * (a_max_tmp >= 0 ? b_min_tmp : b_max_tmp));
Answer = (a_f_max_tmp != INT_MIN ? max(Answer, a_f_max_tmp * (a_f_max_tmp >= 0 ? b_min_tmp : b_max_tmp)) : Answer);
Answer = (a_ff_min_tmp != INT_MAX ? max(Answer, a_ff_min_tmp * (a_ff_min_tmp >= 0 ? b_min_tmp : b_max_tmp)) : Answer);
cout << Answer << endl;
}
return 0;
}
CSDN 你给我推了个游戏的标签什么意思。