[CSP-S 2022] 策略游戏 题解

· · 题解

更好的阅读体验。

题目链接。

思路

题目中重要条件:

小 L 的目标是使得这个得分尽可能大,小 Q 的目标是使得这个得分尽可能小。同时两人都是足够聪明的玩家,每次都会采用最优的策略。

也就是说,小 L 掌握主动权,小 L 选择后小 Q 才会从中选择一个数,使 C_{xy} 尽可能的小,小 L 会从所有可能的 C_{xy} 中选择最大的哪一个。

我们模拟一下都会出现哪些情况。

通过上面的分析,我们发现前 6 种情况都是从两边的最大值和最小值中获得的,只有最后一种情况涉及到了序列 a_i 的正数中的最小值和负数中的最大值。

我们在统计答案的时候只需要从两种极值的选择中取最小值最大的情况,然后判断是否存在第 7 中情况,取最大值即可。

至于两个序列的极值的查询,由于不涉及到修改操作,我们可以用 ST 表来维护两个序列的信息。

ST 表预处理复杂度为 \mathcal O(n\log n+m\log m),ST 表查询复杂度为 \mathcal O(1),总共 q 次查询,所以总时间复杂度为 \mathcal O(n\log n+m\log m +q)。

代码

#include<bits/stdc++.h>
#define int long long
#include<cstdio>
using namespace std;
int n,m,q,a[100010],b[100010];
struct re{
    __int128 a,b,c,d;
};
struct nod{
    __int128 ST1[100010][20],ST2[100010][20],ST3[100010][20],ST4[100010][20];
    void bulid(int *p,int len){
        for(int i=1;i<=len;i++){
            ST1[i][0]=p[i];
            if(p[i]>=0){
                ST2[i][0]=p[i];
            }
            else{
                ST2[i][0]=2e9;
            }
            ST3[i][0]=p[i];
            if(p[i]>0){
                ST4[i][0]=-2e9;
            }
            else{
                ST4[i][0]=p[i];
            }
        }
        for(int j=1;j<=log2(len);j++){
            for(int i=1;i<=len-(1<<j)+1;i++){
                ST1[i][j]=min(ST1[i][j-1],ST1[i+(1<<(j-1))][j-1]);
                ST2[i][j]=min(ST2[i][j-1],ST2[i+(1<<(j-1))][j-1]);
                ST3[i][j]=max(ST3[i][j-1],ST3[i+(1<<(j-1))][j-1]);
                ST4[i][j]=max(ST4[i][j-1],ST4[i+(1<<(j-1))][j-1]);
            }
        }
    }
    re query(int l,int r){
        int len=r-l+1;
        int p=log2(len);
        int a=min(ST1[l][p],ST1[r-(1<<p)+1][p]);
        int b=min(ST2[l][p],ST2[r-(1<<p)+1][p]);
        int c=max(ST3[l][p],ST3[r-(1<<p)+1][p]);
        int d=max(ST4[l][p],ST4[r-(1<<p)+1][p]);
        return re{a,b,c,d};
    }
}ST1,ST2;
signed main(){
    // freopen("game.in","r",stdin);
    // freopen("game.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&q);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<=m;i++){
        scanf("%lld",&b[i]);
    }
    ST1.bulid(a,n);
    ST2.bulid(b,m);
    while(q--){
        int l1,r1,l2,r2;
        scanf("%lld%lld%lld%lld",&l1,&r1,&l2,&r2);
        re tmp1=ST1.query(l1,r1);
        re tmp2=ST2.query(l2,r2);
        int ans=max(min(tmp1.c*tmp2.a,tmp1.c*tmp2.c),min(tmp1.a*tmp2.c,tmp1.a*tmp2.a));
        if(tmp1.b<1e9){
            ans=max(ans,(int)tmp1.b*(int)tmp2.a);
        }
        if(tmp1.d>-1e9){
            ans=max(ans,(int)tmp1.d*(int)tmp2.c);
        }
        printf("%lld\n",ans);
    }
    return 0;
}