Solution - P8818 [CSP-S 2022] 策略游戏

校内模拟赛 T2,恭喜 lijunxi2026 拿下首 A。

赛时被 Hack 在了 #19,但是因为有 100pts 了就没有去管它,后来才调出来。

思路

首先注意小 Q。因为他选择时 \(x\) 已经确定,那么直接选可能造成最小分数的一个即可。
那么注意小 P,显然他的任务是让他选择的 \(x\) 可能造成的最小值最大。(其实是因为我做过类似的题 qwq)

首先想到的是维护两个最小值,然后看到 \(-10^9 \le |a_i|,|b_i| \le 10^9\) 的时候被打脸了。

然后想到维护两个最值,四个 ST 表。然后样例 2 的第三个询问被打脸了。

于是手模样例 2,发现选择是 \((-1, 2)\)。于是想到额外维护 \(a\) 最小的非负数与最大的负数,然后把这一堆东西取最大就行了。

于是,没了。

代码

#include <bits/stdc++.h>
#define rint register int
#define rllong register long long
#define llong long long
#define N 100005
using namespace std;

int Log2[N];
int st1a[N][20], st1b[N][20], st1d[N][20], st1e[N][20], st2a[N][20], st2b[N][20];
int n, m, q;

inline void prework(){
	for(rint i = 2; i <= max(n, m); ++i)
		Log2[i] = Log2[i>>1]+1;
	for(rint t = 1; t <= 19; ++t)
		for(rint i = 1; i <= n; ++i){
			if(i+(1<<t-1) > n) continue;
			st1a[i][t] = min(st1a[i][t-1], st1a[i+(1<<t-1)][t-1]);
			st1b[i][t] = max(st1b[i][t-1], st1b[i+(1<<t-1)][t-1]);
			st1d[i][t] = min(st1d[i][t-1], st1d[i+(1<<t-1)][t-1]);
			st1e[i][t] = max(st1e[i][t-1], st1e[i+(1<<t-1)][t-1]);
		}
	for(rint t = 1; t <= 19; ++t)
		for(rint i = 1; i <= m; ++i){
			if(i+(1<<t-1) > m) continue;
			st2a[i][t] = min(st2a[i][t-1], st2a[i+(1<<t-1)][t-1]);
			st2b[i][t] = max(st2b[i][t-1], st2b[i+(1<<t-1)][t-1]);
		}
}

#define len (r-l+1)
inline int query1a(rint l, rint r){return min(st1a[l][Log2[len]], st1a[r-(1<<Log2[len])+1][Log2[len]]);} // min
inline int query1b(rint l, rint r){return max(st1b[l][Log2[len]], st1b[r-(1<<Log2[len])+1][Log2[len]]);} // max
inline int query1d(rint l, rint r){return min(st1d[l][Log2[len]], st1d[r-(1<<Log2[len])+1][Log2[len]]);} // min
inline int query1e(rint l, rint r){return max(st1e[l][Log2[len]], st1e[r-(1<<Log2[len])+1][Log2[len]]);} // max
inline int query2a(rint l, rint r){return min(st2a[l][Log2[len]], st2a[r-(1<<Log2[len])+1][Log2[len]]);} // min
inline int query2b(rint l, rint r){return max(st2b[l][Log2[len]], st2b[r-(1<<Log2[len])+1][Log2[len]]);} // max

int main(){
	scanf("%d %d %d", &n, &m, &q);
	for(rint i = 1; i <= n; ++i){
		rint x;
		scanf("%d", &x);
		if (x >= 0) st1a[i][0] = x, st1b[i][0] = -1e9-9;
		else        st1b[i][0] = x, st1a[i][0] = 1e9+9;
		st1d[i][0] = st1e[i][0] = x;
	}
	for(rint i = 1; i <= m; ++i)
		scanf("%d", &st2a[i][0]), st2b[i][0] = st2a[i][0];
	prework();
	while(q--){
		rint l1, r1, l2, r2;
		scanf("%d %d %d %d", &l1, &r1, &l2, &r2);
		rllong val = -1e18-3;
		rllong val1 = 1ll*query1a(l1, r1)*(query1a(l1, r1)>=0 ? query2a(l2, r2) : query2b(l2, r2));
		rllong val2 = 1ll*query1b(l1, r1)*(query1b(l1, r1)>=0 ? query2a(l2, r2) : query2b(l2, r2));
		rllong val4 = 1ll*query1d(l1, r1)*(query1d(l1, r1)>=0 ? query2a(l2, r2) : query2b(l2, r2));
		rllong val5 = 1ll*query1e(l1, r1)*(query1e(l1, r1)>=0 ? query2a(l2, r2) : query2b(l2, r2));
		if(query1a(l1, r1) < +1e9) val = max(val, val1);
		if(query1b(l1, r1) > -1e9) val = max(val, val2);
		val = max(val, max(val4, val5));
		printf("%lld\n", val);
	}
	return 0;
}

注意

  • 十年 OI 一场空,不开________见祖宗
  • 务必分清 \(n, m\),我在这里被 Hack 了两个小时……
posted @ 2025-04-21 19:55  Hootime  阅读(12)  评论(0)    收藏  举报