codeforces 1167E

题意:删除原数组中值域为[ l,r ]的数字,使数组中剩下的数单调递增

思路:预处理每个数值的左边界和右边界,那么结果中的形式一定是这样的

           [_____1________]              [______5_______]                  [_____10________]

           3                            7             10                      15                 20                           23

           又因为只能删除一段值域,所以一定有一边一开始就是排好序的,所以我们预处理前缀为上图最长的序列和后缀为上图最长的序列。这两边具有单调性,所以左指针右移时右指针一定右移或不动。有单调性质的序列可以用指针移动来做。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a[1000005],vis[1000005],l[1000005],r[1000005];
vector<LL> ve;
const LL inf = 0x3f3f3f3f3f3f3f3f;
void init( LL n ){
    for( LL i =0;i <= n;i++ ) vis[i]= 0;
}
int main()
{
    LL n,x,ans = 0,mn = inf;
    scanf("%I64d%I64d",&n,&x);
    for( LL i = 1;i <= n;i++ ){
        scanf("%I64d",&a[i]);
        ve.push_back( a[i] );
        mn = min( mn,a[i] );
    }
    sort( ve.begin(),ve.end() );
    init(x);
    for( LL i  = 1;i <= n;i++ ){
        if( !vis[ a[i] ] ){
            vis[ a[i] ] = 1;
            l [ a[i] ] = i;
        }
    }
    init(x);
    for( LL i = n;i >= 1;i-- ){
        if( !vis[ a[i]  ] ){
            vis[ a[i] ] = 1;
            r[ a[i] ] = i;
        }
    }
    auto t = unique( ve.begin(),ve.end() );
    ve.erase( t,ve.end() );
    LL le = 0,ri = ve.size() - 1;
    while( le +1 < ve.size() && l[ ve[le+1] ] > r[ ve[le] ] ) le++;    //指针移动写法                        
    while( ri-1 >= 0 && r[ ve[ri-1] ] < l[ ve[ri] ]  ) ri--;
    if( le >= ri ){
        printf("%I64d",x*( x-1 )/2 + x);
        return 0;
    }
    ans += (ve[0] - 1 - 1 + 2) *( x - (ve[ri-1]+1)+2 );
    LL L = 0,R = ri;
    for( ; L < ve.size() && L <= le;L++ ){
        while( R < ve.size() && l[ ve[R] ] <= r[ ve[L] ] ) R++;   //指针移动写法
        ans += (x - (ve[R-1] +1) + 2) *( ve[L+1] - 1 - (ve[L] + 1) + 2 );
    }
    printf("%I64d\n",ans);
    return 0;
}
/* 10 100
1 5 6 6 9 5 5 3 2 6
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值