Codeforces 689D Friends and Subsequences(二分+RMQ)

3 篇文章 0 订阅
2 篇文章 0 订阅

题意:给两个数列a,数列b,求有多少个区间[l,r],使得a区间的最大值等于b区间的最小值

题解:首先,满足


maxi=lraimini=lrbimaxi=lr+1aimini=lr+1bi

           因为左端点固定,区间越大,最大值越大,区间越大,最小值越小。


           然后就可以枚举左端点,二分右端点,求出所有的max-min == 0即可,区间查询采用RMQ

const int MAX = 200010;

int a[MAX],b[MAX];
int aa[MAX][25],bb[MAX][25];
int n;

void rmq_inita(){
    for(int i=0;i<n;i++)
        aa[i][0]=a[i];
    for(int j=1;(1<<j)<=n;j++){
        for(int i=0;i+(1<<j)-1<n;i++){
            aa[i][j]=max(aa[i][j-1],aa[i+(1<<(j-1))][j-1]);
        }
    }
}

void rmq_initb(){
    for(int i=0;i<n;i++)
        bb[i][0]=b[i];
    for(int j=1;(1<<j)<=n;j++){
        for(int i=0;i+(1<<j)-1<n;i++){
            bb[i][j]=min(bb[i][j-1],bb[i+(1<<(j-1))][j-1]);
        }
    }
}

int rmqa(int L,int R){
    int k=0;
    while((1<<(k+1))<=R-L+1)
        k++;
    return max(aa[L][k],aa[R-(1<<k)+1][k]);
}

int rmqb(int L,int R){
    int k=0;
    while((1<<(k+1))<=R-L+1)
        k++;
    return min(bb[L][k],bb[R-(1<<k)+1][k]);
}

int main(){
    while(cin>>n){
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<n;i++)
            scanf("%d",&b[i]);
        rmq_inita();
        rmq_initb();
        LL ans=0;
        for(int i=0;i<n;i++){
            int l=i,r=n-1;
            while(l<=r){
                int mid=(l+r)/2;
                if(rmqa(i,mid)-rmqb(i,mid)<0) l=mid+1;
                else r=mid-1;
            }
            ans-=l;
            l=i,r=n-1;
            while(l<=r){
                int mid=(l+r)/2;
                if(rmqa(i,mid)-rmqb(i,mid)<=0) l=mid+1;
                else r=mid-1;
            }
            ans+=l;
        }
        cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值