[CSP-S 2022] 策略游戏
题目描述
小 L 和小 Q 在玩一个策略游戏。
有一个长度为 nnn 的数组 AAA 和一个长度为 mmm 的数组 BBB,在此基础上定义一个大小为 n×mn \times mn×m 的矩阵 CCC,满足 Cij=Ai×BjC_{i j} = A_i \times B_jCij=Ai×Bj。所有下标均从 111 开始。
游戏一共会进行 qqq 轮,在每一轮游戏中,会事先给出 444 个参数 l1,r1,l2,r2l_1, r_1, l_2, r_2l1,r1,l2,r2,满足 1≤l1≤r1≤n1 \le l_1 \le r_1 \le n1≤l1≤r1≤n、1≤l2≤r2≤m1 \le l_2 \le r_2 \le m1≤l2≤r2≤m。
游戏中,小 L 先选择一个 l1∼r1l_1 \sim r_1l1∼r1 之间的下标 xxx,然后小 Q 选择一个 l2∼r2l_2 \sim r_2l2∼r2 之间的下标 yyy。定义这一轮游戏中二人的得分是 CxyC_{x y}Cxy。
小 L 的目标是使得这个得分尽可能大,小 Q 的目标是使得这个得分尽可能小。同时两人都是足够聪明的玩家,每次都会采用最优的策略。
请问:按照二人的最优策略,每轮游戏的得分分别是多少?
输入格式
第一行输入三个正整数 n,m,qn, m, qn,m,q,分别表示数组 AAA,数组 BBB 的长度和游戏轮数。
第二行:nnn 个整数,表示 AiA_iAi,分别表示数组 AAA 的元素。
第三行:mmm 个整数,表示 BiB_iBi,分别表示数组 BBB 的元素。
接下来 qqq 行,每行四个正整数,表示这一次游戏的 l1,r1,l2,r2l_1, r_1, l_2, r_2l1,r1,l2,r2。
输出格式
输出共 qqq 行,每行一个整数,分别表示每一轮游戏中,小 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】
这组数据中,矩阵 CCC 如下:
[00−346−8] \begin{bmatrix} 0 & 0 \\ -3 & 4 \\ 6 & -8 \end{bmatrix} ⎣⎡0−3604−8⎦⎤
在第一轮游戏中,无论小 L 选取的是 x=2x = 2x=2 还是 x=3x = 3x=3,小 Q 都有办法选择某个 yyy 使得最终的得分为负数。因此小 L 选择 x=1x = 1x=1 是最优的,因为这样得分一定为 000。
而在第二轮游戏中,由于小 L 可以选 x=2x = 2x=2,小 Q 只能选 y=2y = 2y=2,如此得分为 444。
【样例 #3】
见附件中的 game/game3.in 与 game/game3.ans。
【样例 #4】
见附件中的 game/game4.in 与 game/game4.ans。
【数据范围】
对于所有数据,1≤n,m,q≤1051 \le n, m, q \le {10}^51≤n,m,q≤105,−109≤Ai,Bi≤109-{10}^9 \le A_i, B_i \le {10}^9−109≤Ai,Bi≤109。对于每轮游戏而言,1≤l1≤r1≤n1 \le l_1 \le r_1 \le n1≤l1≤r1≤n,1≤l2≤r2≤m1 \le l_2 \le r_2 \le m1≤l2≤r2≤m。
| 测试点编号 | n,m,q≤n, m, q \len,m,q≤ | 特殊条件 |
|---|---|---|
| 111 | 200200200 | 1, 2 |
| 222 | 200200200 | 1 |
| 333 | 200200200 | 2 |
| 4∼54 \sim 54∼5 | 200200200 | 无 |
| 666 | 100010001000 | 1, 2 |
| 7∼87 \sim 87∼8 | 100010001000 | 1 |
| 9∼109 \sim 109∼10 | 100010001000 | 2 |
| 11∼1211 \sim 1211∼12 | 100010001000 | 无 |
| 131313 | 105{10}^5105 | 1, 2 |
| 14∼1514 \sim 1514∼15 | 105{10}^5105 | 1 |
| 16∼1716 \sim 1716∼17 | 105{10}^5105 | 2 |
| 18∼2018 \sim 2018∼20 | 105{10}^5105 | 无 |
其中,特殊性质 1 为:保证 Ai,Bi>0A_i, B_i > 0Ai,Bi>0。
特殊性质 2 为:保证对于每轮游戏而言,要么 l1=r1l_1 = r_1l1=r1,要么 l2=r2l_2 = r_2l2=r2。
分析:
题目要求,即给第一个人一个子序列、给第二个人另一个子序列,要求两个人先后各选一个数,其中第一个人要让最后得到的两个数乘积尽可能大,而第二个人反之。显然,第一个人的行为要取决于第二个人能取到哪些数,而第二个人的行为取决于第一个人选了什么数,于是我们要分类讨论:
1.1.1. 第二个人只能取到正数。
那么,第一个人就要欺负第二个人取不到负数,那么他必然会取自己所能取到的最大正数,那么第二个人就会取自己能取到的最小正数来使乘积最小。当然,如果第一个人只能取到负数,那么他就会取自己能取到的最大负数来使乘积尽量不那么小,而第二个人就会取最大正数来使乘积最小。
2.2.2. 第二个人只能取到负数。
类似第一种情况,读者不妨自己试着推一推。
3.3.3. 第二个人能取到正数或负数。
对于这种情况,第二个人就有了最后乘积正负性的决定权。当然,为了使乘积最小,他肯定会使最后的乘积为负数,此时我们再根据第一个人的取值范围分类讨论:一,第一个人只能取到正值,那么他必将选择最小的那个,因为第二个人肯定会选最小负值来使乘积最小。二,第一个人只能取到负值,那么同理,他会选择最大的负值。三,第一个人可以取到正值和负值,那么如果他选了正值,第二个人就会取最小负值;如果他选了负值,第二个人就会取最大正值。于是,第一个人就会根据这两种情况最后得到的乘积大小比较来决定自己是选最大负值还是最小正值。
对于 000 ,可以以上述讨论中的任何方式处理,无需特殊考虑。
对于最大值和最小值之类的高效查询,使用 SSS TTT 表无疑是最佳的。
时间复杂度:
SSS TTT 表建表: O(nlogn)O(n\log n)O(nlogn)
查询: O(q)O(q)O(q)
总时间复杂度:O(nlogn)O(n\log n)O(nlogn)
代码打的有点丑,不过变量大部分用拼音首字母打的,应该比较好理解。
Code:
#include<bits/stdc++.h>
using namespace std;
long long n,m,q,l1,l2,r1,r2,a[100010],b[100010],qr[100010][5];
long long st1max[100010][20],st1min[100010][20],n2[20],st2max[100010][20],st2min[100010][20];
long long st1zdfz[100010][20],st1zxzz[100010][20];
int main(){
cin>>n>>m>>q;
for(long long i=1;i<=n;++i){
cin>>a[i];
}
for(long long i=1;i<=m;++i){
cin>>b[i];
}
for(long long i=1;i<=q;++i){
cin>>qr[i][1]>>qr[i][2]>>qr[i][3]>>qr[i][4];
}
n2[0]=1;
for(long long i=1;i<20;++i) n2[i]=n2[i-1]*2;
for(long long i=1;i<=n;++i) st1max[i][0]=st1min[i][0]=a[i],st1zdfz[i][0]=(a[i]>0?-1e9:a[i]),st1zxzz[i][0]=(a[i]>0?a[i]:1e9);
for(long long i=1;i<=m;++i) st2max[i][0]=st2min[i][0]=b[i];
for(long long i=1;n2[i]<=n;++i){
for(long long j=1;j+n2[i]-1<=n;++j){
st1max[j][i]=max(st1max[j][i-1],st1max[j+n2[i-1]][i-1]);
st1zdfz[j][i]=max(st1zdfz[j][i-1],st1zdfz[j+n2[i-1]][i-1]);
st1min[j][i]=min(st1min[j][i-1],st1min[j+n2[i-1]][i-1]);
st1zxzz[j][i]=min(st1zxzz[j][i-1],st1zxzz[j+n2[i-1]][i-1]);
}
}
for(long long i=1;n2[i]<=m;++i){
for(long long j=1;j+n2[i]-1<=m;++j){
st2max[j][i]=max(st2max[j][i-1],st2max[j+n2[i-1]][i-1]);
st2min[j][i]=min(st2min[j][i-1],st2min[j+n2[i-1]][i-1]);
}
}
for(long long i=1;i<=q;++i){
long long len1=qr[i][2]-qr[i][1]+1,len2=qr[i][4]-qr[i][3]+1;
long long lgn1=floor(log2(len1)),lgn2=floor(log2(len2));
long long z1=max(st1max[qr[i][1]][lgn1],st1max[qr[i][2]-n2[lgn1]+1][lgn1]);
long long f1=min(st1min[qr[i][1]][lgn1],st1min[qr[i][2]-n2[lgn1]+1][lgn1]);
long long z2=max(st2max[qr[i][3]][lgn2],st2max[qr[i][4]-n2[lgn2]+1][lgn2]);
long long f2=min(st2min[qr[i][3]][lgn2],st2min[qr[i][4]-n2[lgn2]+1][lgn2]);
long long zdfz1=max(st1zdfz[qr[i][1]][lgn1],st1zdfz[qr[i][2]-n2[lgn1]+1][lgn1]);
long long zxzz1=min(st1zxzz[qr[i][1]][lgn1],st1zxzz[qr[i][2]-n2[lgn1]+1][lgn1]);
if(f2>=0){
if(z1>=0) cout<<z1*f2<<endl;
else cout<<zdfz1*z2<<endl;
}
else if(z2<=0){
if(f1<=0) cout<<z2*f1<<endl;
else cout<<zxzz1*f2<<endl;
}
else{
if(z1<=0) cout<<z1*z2<<endl;
else if(f1>=0) cout<<f1*f2<<endl;
else cout<<max(zxzz1*f2,zdfz1*z2)<<endl;
}
}
fclose(stdin);
fclose(stdout);
return 0;
}
这篇博客详细介绍了CSP-S 2022中的一道策略游戏问题,涉及两个玩家在给定数组A和B的基础上构建矩阵C,并进行多轮游戏以最大化或最小化每轮的得分。玩家需要根据对手的选择策略来确定自己的最佳选择。博客内容包括问题描述、输入输出格式、样例和分析,以及解决方案的时间复杂度。
2143

被折叠的 条评论
为什么被折叠?



