AtCoder Beginner Contest 377 D题题解

题目传送门
可以看到题目给出的 L i L_i Li R i R_i Ri其实规定的是 l l l小于等于 L i L_i Li r r r必须小于 R i R_i Ri。因此我们只要求出 i i i l l l时最大的 r r r,然后把他们的区间的数字数量加起来,可是这样的时间复杂度接近 O ( n m ) O(nm) O(nm),能不能再优化呢?当然可以,既然是小于等与 L i L_i Li的数都被限制,那么为什么不可以 a i a_i ai为当 l l l小于等于 i i i r r r的最大取值呢:在每次输入 L i L_i Li R i R_i Ri时设置 a L i = m i n ( a i , R i − 1 ) a_{L_i}=min(a_i,R_i-1) aLi=min(ai,Ri1),然后从后往前遍历每一个数让 a n s ans ans加上 i i i和它最大右端点的取值就可以了(如果从前往后的话会出现 a a a数组后面的元素小于前面的元素的情况,而从后往前我们只需要忽略掉前面比他大的元素就可以了)。

代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,s,ans,a[500005];
//a[i]为当l小于等于i时r的最大取值 
main(){
    cin>>m>>n; 
    memset(a,-1,sizeof a);
    a[n]=n;
    while(m--){
        int l,r;
        cin>>l>>r;
        if(a[l]==-1){
            //直接赋值 
            a[l]=r-1;
        }else{
            //找到最小的r的最大取值 
            a[l]=min(r-1,a[l]);
        }
    }
    //s是当前的最大r的最大取值 
    s=a[n];
    for(int i=n;i>=1;i--){
        //当前面的r的最大取值比当前的苛刻就更新s 
        if(s>a[i]&&a[i]!=-1){
            s=a[i];
        }
        //ans加上从l到r一共可选的总数 
        ans+=(s-i+1);
    }
    cout<<ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值