洛谷P8818 [CSP-S 2022] 策略遊戲

一位XXS發表於2024-10-13

Problem

給出兩個陣列A,B,進行q次詢問,每次分別給出這兩個陣列的某個區間l1,r1,l2,r2,也就是\(A_{l1 \sim r1}\)\(B_{l2\sim r2}\),有兩位同學小L和小Q分別從A,B的以上區間中選一個數,而兩數乘積為此次操作的分數,小L希望分數大,小Q希望分數小,請問他們每次以最優策略進行遊戲,分數將會是多少?(小L先選,且小Q知道小L選了什麼)
其中\(1\le n,m,q\le 10^5\)

Solve

不難發現小L如果選了正數,小Q會選最小的數,反之亦然。
但是小L作為先手肯定預判了他的預判,所以他會在腦海中模擬如果選 正數max 正數min 負數max 負數min 小L會選什麼,然後計算模擬的四種情況的得分,取最大的方案即可。
然後A,B陣列的最值可以直接用ST表維護,對於每個ST表如果有不符合正負的元素直接變成inf或-inf即可。
時間複雜度\(O(n\log n+m\log m)\)

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
const long long INF=0x3f3f3f3f3f3f3f3f;
long long n,m,q,a[100005],b[100005];
long long m1[100005][22],m2[100005][22],m3[100005][22],m4[100005][22];//正max/min 負max/min
long long m5[100005][22],m6[100005][22],lg[100005];//max/min
void init(){
    for(int i=1;i<=n;i++)m2[i][0]=INF,m3[i][0]=-INF,m4[i][0]=INF;
    for(int i=1;i<=m;i++)m5[i][0]=-INF,m6[i][0]=INF;
    for(int i=2;i<=max(n,m);i++){
        lg[i]=lg[i/2]+1;
    }
}
long long pow(long long x){
    return 1<<x;
}
long long qlr(int l,int r,int type){
    if(type==1)return max(m1[l][lg[r-l+1]],m1[r-pow(lg[r-l+1])+1][lg[r-l+1]]);
    if(type==2)return min(m2[l][lg[r-l+1]],m2[r-pow(lg[r-l+1])+1][lg[r-l+1]]);
    if(type==3)return max(m3[l][lg[r-l+1]],m3[r-pow(lg[r-l+1])+1][lg[r-l+1]]);
    if(type==4)return min(m4[l][lg[r-l+1]],m4[r-pow(lg[r-l+1])+1][lg[r-l+1]]);
    if(type==5)return max(m5[l][lg[r-l+1]],m5[r-pow(lg[r-l+1])+1][lg[r-l+1]]);
    if(type==6)return min(m6[l][lg[r-l+1]],m6[r-pow(lg[r-l+1])+1][lg[r-l+1]]);
}
int main(){
    cin>>n>>m>>q;
    init();
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(a[i]>0){
            m1[i][0]=a[i];
            m2[i][0]=a[i];
        }else {
            m3[i][0]=a[i];
            m4[i][0]=a[i];
        }
    }
    for(int i=1;i<=m;i++){
        cin>>b[i];
        m5[i][0]=b[i];
        m6[i][0]=b[i];
    }
    for(int j=1;j<=lg[n];j++){
        for(int i=1;i<=n;i++){
            if(i+pow(j)-1>n)break;
            m1[i][j]=max(m1[i][j-1],m1[i+pow(j-1)][j-1]);
            m3[i][j]=max(m3[i][j-1],m3[i+pow(j-1)][j-1]);
            m2[i][j]=min(m2[i][j-1],m2[i+pow(j-1)][j-1]);
            m4[i][j]=min(m4[i][j-1],m4[i+pow(j-1)][j-1]);
        }
    }
    for(int j=1;j<=lg[m];j++){
        for(int i=1;i<=m;i++){
            if(i+pow(j)-1>m)break;
            m5[i][j]=max(m5[i][j-1],m5[i+pow(j-1)][j-1]);
            m6[i][j]=min(m6[i][j-1],m6[i+pow(j-1)][j-1]);
        }
    }
    while(q--){
        long long l1,r1,l2,r2,t1=-INF,t2=-INF,t3=-INF,t4=-INF;
        cin>>l1>>r1>>l2>>r2;
        if(qlr(l1,r1,1)>0){
            t1=qlr(l1,r1,1)*qlr(l2,r2,6);
            t2=qlr(l1,r1,2)*qlr(l2,r2,6);
        }
        if(qlr(l1,r1,4)<=0){
            t3=qlr(l1,r1,3)*qlr(l2,r2,5);
            t4=qlr(l1,r1,4)*qlr(l2,r2,5);
        }
        cout<<max(max(t1,t2),max(t3,t4))<<endl;
    }
    return 0;
}