codeforces1167 E. Range Deleting(双指针)

E. Range Deleting

首先不难知道如果 f ( l , r ) f(l,r) f(l,r)满足题意,那么 f ( l , r + 1 ) , f ( l , r + 2 ) , … , f ( l , x ) f(l,r+1),f(l,r+2),\dots,f(l,x) f(l,r+1),f(l,r+2),,f(l,x)都满足题意。
因而对于每一个左端点 l l l,需要找到最小的一个右端点 r r r

单调性:对于每一个左端点 l l l,当左端点右移(增大)的过程中,右端点也一定右移(增大)
有了上述单调性考虑双指针表示 f ( i , j ) f(i,j) f(i,j)

预处理出以下数组
①:l[i]值是i的最小数组下标
②:r[i]值是i的最大数组下标
③:ll[i]值是i~x的最小数组下标
④:rr[i]值是1~i的最大数组下标

对于一个区间 [ l , r ] [l,r] [l,r],假设值在 [ 1 , l − 1 ] [1,l-1] [1,l1]以及 [ r + 1 , x ] [r+1,x] [r+1,x]内部不存在逆序对,只需要判断 [ 1 , l − 1 ] [1,l-1] [1,l1] [ r + 1 , x ] [r+1,x] [r+1,x]之间是否存在逆序对即值在 [ 1 , l − 1 ] [1,l-1] [1,l1]最大数组下标是否大于 [ r + 1 , x ] [r+1,x] [r+1,x]最小数组下标即如果存在逆序对(rr[l-1]<ll[r+1])不满足条件,只需根据此调整双指针位置。

对于假设条件,显然可以求出对于 [ 1 , p l ) [1,pl) [1,pl)内部不存在逆序对,以及 ( p r , x ] (pr,x] (pr,x]内部不存在逆序对,因而只需要让指针 i i i [ 1 , p l ] [1,pl] [1,pl]之间,而指针 j j j [ p r , x ] [pr,x] [pr,x]之间即可。

#define IO ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
#pragma GCC optimize(2)
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
constexpr int N=1000010;
int a[N],n,x;
int l[N],r[N],ll[N],rr[N];
int main()
{
    
    
    IO;
    cin>>n>>x;
    memset(l,0x3f,sizeof l);
    memset(ll,0x3f,sizeof ll);
    memset(r,-1,sizeof r);
    memset(rr,-1,sizeof rr);
    
    for(int i=1;i<=n;i++)
    {
    
    
        cin>>a[i];
        l[a[i]]=min(l[a[i]],i);
        r[a[i]]=max(r[a[i]],i);
    }
    // rr[i] 1~i最右边的位置
    // ll[i] i~x最左边的位置
    for(int i=1;i<=x;i++) rr[i]=max(rr[i-1],r[i]);
    for(int i=x;i>=1;i--) ll[i]=min(ll[i+1],l[i]);
    long long res=0;
    // [1,pl) 以及 (pr,x] 不存在逆序对
    int pl=1,pr=x;
    while(pl<=x&&rr[pl-1]<=l[pl]) pl++;
    while(pr>=1&&ll[pr+1]>=r[pr]) pr--; 
    for(int i=1,j=pr;i<=pl;i++)
    {
    
    
        while(j<=x&&(j<i||rr[i-1]>=ll[j+1])) j++;
        res+=x-j+1;
    }
    cout<<res<<'\n';
    return 0;
}

要加油哦~

猜你喜欢

转载自blog.csdn.net/Fighting_Peter/article/details/113789136