[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。
整体思路
概括题意:
在两个不同的区间里面选取两个数字,结果可以拆分为两个子问题:
1.让两个数的乘积最小(Q)
2.让两个数的乘积最大(L)
可以固定下来一个人选大的数还是小的数,让后让另一个人跟着他走一遍模拟。
这里我们选取暴力枚举L:
当L选取的数为正数的时候,q就要让他选择尽量小一点得数;
当L选的是负数的时候,Q便要选尽量大一些的数;
当L选取的数为0,那么便不用顾忌Q(反正最后的乘积都要为0)
分类讨论,依次处理即可。
ac代码
#include <bits/stdc++.h>
#define ET return 0
#define fr1(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define fr2(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)
#define ll long long
#define mp make_pair
#define il inline
#define pii pair<int,int>
#define fi first
#define se second
#define il inline
#define int ll
using namespace std;
const int N=1e5+10;
int n,m,q;
int a[N],b[N];
int l1,r1,l2,r2;
#define mid ((l+r)>>1)
struct node{int maxf,minf,maxz,minz,cnt0;
};
struct Segment_Tree{int val[N<<2],minn[N<<2],maxn[N<<2],maxf[N<<2],minf[N<<2],maxz[N<<2],minz[N<<2],cnt0[N<<2];void pushup(int p){minn[p]=min(minn[p<<1],minn[p<<1|1]);maxn[p]=max(maxn[p<<1],maxn[p<<1|1]);maxf[p]=max(maxf[p<<1],maxf[p<<1|1]);minf[p]=min(minf[p<<1],minf[p<<1|1]);maxz[p]=max(maxz[p<<1],maxz[p<<1|1]);minz[p]=min(minz[p<<1],minz[p<<1|1]);cnt0[p]=cnt0[p<<1]+cnt0[p<<1|1];}void merge(node &ans,node d){ans.cnt0+=d.cnt0;ans.maxf=max(ans.maxf,d.maxf);ans.minf=min(ans.minf,d.minf);ans.maxz=max(ans.maxz,d.maxz);ans.minz=min(ans.minz,d.minz);}il void build(int p,int l,int r){maxf[p]=LONG_LONG_MIN;minf[p]=0;maxz[p]=0;cnt0[p]=0;minz[p]=LONG_LONG_MAX;if(l==r){minn[p]=maxn[p]=val[l];if(val[l]<0){maxf[p]=val[l];minf[p]=val[l];}else if(val[l]>0){maxz[p]=val[l];minz[p]=val[l];}else{cnt0[p]=1;}return;}build(p<<1,l,mid);build(p<<1|1,mid+1,r);pushup(p);}//建树 il pii query(int p,int l,int r,int ml,int mr){if(ml<=l&&r<=mr){return mp(minn[p],maxn[p]);}pii ans=mp(LONG_LONG_MAX,LONG_LONG_MIN);if(ml<=mid){pii d=query(p<<1,l,mid,ml,mr);ans.fi=min(ans.fi,d.fi);ans.se=max(ans.se,d.se);}if(mid<mr){pii d=query(p<<1|1,mid+1,r,ml,mr);ans.fi=min(ans.fi,d.fi);ans.se=max(ans.se,d.se);}return ans;}il node queryb(int p,int l,int r,int ml,int mr){if(ml<=l&&r<=mr){return {maxf[p],minf[p],maxz[p],minz[p],cnt0[p]};}node ans={LONG_LONG_MIN,0,0,LONG_LONG_MAX,0};if(ml<=mid){node d=queryb(p<<1,l,mid,ml,mr);merge(ans,d);}if(mid<mr){node d=queryb(p<<1|1,mid+1,r,ml,mr);merge(ans,d);}return ans;}
} T1,T2;//树形结构的基本操作
#undef mid
void solve2(){while(q--){int ans=LONG_LONG_MIN; cin>>l1>>r1>>l2>>r2;node d=T1.queryb(1,1,n,l1,r1);int x=T2.query(1,1,m,l2,r2).fi;int y=T2.query(1,1,m,l2,r2).se;if(d.cnt0!=0){ans=0;}if(y>0&&d.minf!=0){ans=max(ans,y*d.maxf);}if(y<=0&&d.maxf!=LONG_LONG_MIN){ans=max(ans,y*d.minf);}if(x<=0&&d.minz!=LONG_LONG_MAX){ans=max(ans,x*d.minz);}if(x>0&&d.maxz!=0){ans=max(ans,x*d.maxz);}cout<<ans<<'\n';}
}//问题处理
signed main(){ios::sync_with_stdio(false);cin>>n>>m>>q;fr1(i,1,n){cin>>a[i];T1.val[i]=a[i];}fr1(i,1,m){cin>>b[i];T2.val[i]=b[i];}T1.build(1,1,n);T2.build(1,1,m);solve2();ET;