【题解】CSP-S2022 T2策略游戏
简要题意
有两串数A[1 n],B[1 m]A[1 n],B[1 m],有两个人小L和小QL和小Q,给出q组l1,r1,l2,r2q组l1,r1,l2,r2,对于每组,小L在A[l1 r1]A[l1 r1]中取一数x,小Q在B[l2 r2]B[l2 r2]中取一数y,小L想使xy最大,小Q想使xy最小,求xy
n,m,q<=105n,m,q<=105
算法1
(朴素想法) O(qnlogm)O(qnlogm)
考虑A[l1 r1]A[l1 r1]中每一个数,建一棵线段树(或ST表),再求出最小值,取最小值的最大输出即可
得分:60
C++ 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n,m,q;
LL a[1010],b[1010];
struct xxx{
    LL l,r;
    LL mn;
}tr[1010][4010];
LL read()
{
    LL s=0,w=1;
    char ch=getchar();
    while('0'>ch||ch>'9')w=ch=='-'?(-w):w,ch=getchar();
    while('0'<=ch&&ch<='9')s=s*10+ch-'0',ch=getchar();
    return s*w;
}
void write(LL x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
void pushup(LL x,LL u)
{
    tr[x][u].mn=min(tr[x][u<<1].mn,tr[x][u<<1|1].mn);
}
void build(LL x,LL u,LL l,LL r)
{
    tr[x][u]={l,r};
    if(l==r)tr[x][u].mn=a[x]*b[l];
    else{
        LL mid=l+r>>1;
        build(x,u<<1,l,mid),build(x,u<<1|1,mid+1,r);
        pushup(x,u);
    }
}
LL query(LL x,LL u,LL l,LL r)
{
    if(l<=tr[x][u].l&&tr[x][u].r<=r)return tr[x][u].mn;
    LL mid=tr[x][u].l+tr[x][u].r>>1,mn=LLONG_MAX;
    if(l<=mid)mn=query(x,u<<1,l,r);
    if(mid<r)mn=min(mn,query(x,u<<1|1,l,r));
    return mn;
}
int main()
{
    LL i,j;
    n=read(),m=read(),q=read();
    for(i=1;i<=n;++i)a[i]=read();
    for(i=1;i<=m;++i)b[i]=read();
    for(i=1;i<=n;++i)build(i,1,1,m);
    while(q--){
        LL l1=read(),r1=read(),l2=read(),r2=read(),mx=LLONG_MIN;
        for(i=l1;i<=r1;++i){
            LL mn=query(i,1,l2,r2);
            if(mx<mn)mx=mn;
        }
        write(mx),putchar('\n');
    }
}
算法2
(st表) O(nlogn)O(nlogn)
此题从博弈论上来讲并不算难题,因为每组最多取两次。
先考虑小Q,若小L取的数x>=0x>=0,则小Q必然取B[l2 r2]B[l2 r2]中的最小值,若小L取的数x<0x<0,则小Q必然取B[l2 r2]B[l2 r2]中的最大值。
接着考虑小L:
1.x>=0x>=0
则小Q必然取最小,设最小值为mn。
若mn>=0,则小L必然取>=0的最大值(可能不存在),否则小L取>=0的最小值。
2.x<0x<0
则小Q必然取最大,设最小值为mx。
若mx>=0,则小L必然取<0的最大值(可能不存在),否则小L取<0的最小值。
如何维护mn、mx、>=0的最大值,>=0的最小值,<0的最大值,<0的最小值mn、mx、>=0的最大值,>=0的最小值,<0的最大值,<0的最小值?
可以用6个ST表,对于不存在的情况记为-INF或INF即可,代码也不难实现,读者请自行完成
时间复杂度
ST表时间复杂度为O(nlogn)O(nlogn),总时间复杂度为O(nlogn+mlogm+qlogn)O(nlogn+mlogm+qlogn),约为O(nlogn)O(nlogn)
C++ 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF=1e9+1;
LL n,m,q;
LL a[100010],b[100010];
LL fb1[100010][18],fb2[100010][18],fa11[100010][18],fa12[100010][18],fa21[100010][18],fa22[100010][18];
//fb1:b中的max,fb2:b中的min,fa11:a中>=0的max,fa12:a中>=0的min,fa21:a中<0的max,fa22:a中<0的min 
LL query(LL l,LL r,LL t)
{
    LL k=log2(r-l+1);
    if(t==1)return max(fb1[l][k],fb1[r-(1<<k)+1][k]);
    else if(t==2)return min(fb2[l][k],fb2[r-(1<<k)+1][k]);
    else if(t==3)return max(fa11[l][k],fa11[r-(1<<k)+1][k]);
    else if(t==4)return min(fa12[l][k],fa12[r-(1<<k)+1][k]);
    else if(t==5)return max(fa21[l][k],fa21[r-(1<<k)+1][k]);
    else return min(fa22[l][k],fa22[r-(1<<k)+1][k]);
}
int main()
{
    LL i,j;
    cin>>n>>m>>q;
    for(i=1;i<=n;i++)cin>>a[i];
    for(i=1;i<=m;i++)cin>>b[i];
    for(j=0;j<=16;j++)
        for(i=1;i+(1<<j)-1<=m;i++)
            if(!j)fb1[i][j]=fb2[i][j]=b[i];
            else{
                fb1[i][j]=max(fb1[i][j-1],fb1[i+(1<<j-1)][j-1]);
                fb2[i][j]=min(fb2[i][j-1],fb2[i+(1<<j-1)][j-1]);
            }
    for(j=0;j<=16;j++)
        for(i=1;i+(1<<j)-1<=n;i++)
            if(!j){
                if(a[i]>=0){
                    fa21[i][j]=-INF;
                    fa22[i][j]=INF;
                    fa11[i][j]=fa12[i][j]=a[i];
                }
                else{
                    fa11[i][j]=-INF;
                    fa12[i][j]=INF;
                    fa21[i][j]=fa22[i][j]=a[i];
                }
            }
            else{
                fa11[i][j]=max(fa11[i][j-1],fa11[i+(1<<j-1)][j-1]);
                fa12[i][j]=min(fa12[i][j-1],fa12[i+(1<<j-1)][j-1]);
                fa21[i][j]=max(fa21[i][j-1],fa21[i+(1<<j-1)][j-1]);
                fa22[i][j]=min(fa22[i][j-1],fa22[i+(1<<j-1)][j-1]);
            }
    while(q--){
        LL l1,r1,l2,r2;
        cin>>l1>>r1>>l2>>r2; 
        LL mxb=query(l2,r2,1),mnb=query(l2,r2,2),ans=LLONG_MIN;
        if(query(l1,r1,3)>=0)ans=max(ans,query(l1,r1,3)*mnb);
        if(query(l1,r1,4)<INF)ans=max(ans,query(l1,r1,4)*mnb);
        if(query(l1,r1,5)>-INF)ans=max(ans,query(l1,r1,5)*mxb);
        if(query(l1,r1,6)<0)ans=max(ans,query(l1,r1,6)*mxb);
        cout<<ans<<endl;
    }
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号