【学习笔记】CF1693E Outermost Maximums

可惜,考场上差点就把这道*3400切掉了。

考虑倒着做,每次等价于将一个满足 a i = max ⁡ j ≤ i a j a_i=\max_{j\le i} a_j ai=maxjiaj或者 a i = max ⁡ j ≥ i a j a_i=\max_{j\ge i} a_j ai=maxjiaj的位置上的 a i a_i ai变成一个大于 a i a_i ai的数 x x x

发现 x x x是单调不降的,因此从小到大考虑每一个数

考虑对于每个位置维护 { l i } , { r i } \{l_i\},\{r_i\} {li},{ri}分别表示这个数成为前缀最大值或者后缀最大值的最小代价,那么对于当前扫描到的权值,记录其出现的最左边的位置为 L L L,最右边的位置为 R R R,那么每次操作等价于:

1.1 1.1 1.1 [ L , n ] [L,n] [L,n]中的 l i l_i li加上 1 1 1
1.2 1.2 1.2 [ 1 , R ] [1,R] [1,R]中的 r i r_i ri加上 1 1 1
1.3 1.3 1.3 [ 1 , R ] [1,R] [1,R]中的 l i l_i li变成 min ⁡ ( l i , r i ) \min(l_i,r_i) min(li,ri)
1.4 1.4 1.4 [ L , n ] [L,n] [L,n]中的 r i r_i ri变成 min ⁡ ( l i , r i ) \min(l_i,r_i) min(li,ri)

线段树+矩阵乘法即可。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

remark \text{remark} remark 感觉自己还是不够冷静,考试的时候有点着急。其实这种模拟赛的成绩大可不必看得那么重。还是应该相信自己的实力的。

#include
#define ll long long
#define pb push_back
#define fi first
#define se second
#define inf 0x3f3f3f3f
using namespace std;
const int N=2e5+5;
int n,a[N];
vector<int>nums[N];
int sz;
ll res;
struct Data{
    int a11,a12,a21,a22,a33;
    Data(int _a11=0,int _a12=inf,int _a21=inf,int _a22=0,int _a33=0){a11=_a11,a12=_a12,a21=_a21,a22=_a22,a33=_a33;}
    Data operator +(const Data &r)const{
        Data res;
        res.a11=min(a11+r.a11,a12+r.a21);
        res.a12=min(a11+r.a12,a12+r.a22);
        res.a21=min(a21+r.a11,a22+r.a21);
        res.a22=min(a21+r.a12,a22+r.a22);
        res.a33=a33+r.a33;
        return res;
    }
};
Data t[N<<2];
void pushdown(int p){
    t[p<<1]=t[p<<1]+t[p],t[p<<1|1]=t[p<<1|1]+t[p];
    t[p].a11=t[p].a22=t[p].a33=0,t[p].a12=t[p].a21=inf;
}
void update(int p,int l,int r,int ql,int qr,Data x){
    if(ql<=l&&r<=qr){
        t[p]=t[p]+x;
        return;
    }
    int mid=l+r>>1;pushdown(p);
    if(ql<=mid)update(p<<1,l,mid,ql,qr,x);
    if(mid<qr)update(p<<1|1,mid+1,r,ql,qr,x);
}
int query(int p,int l,int r,int x){
    if(l==r)return min({t[p].a11,t[p].a12,t[p].a21,t[p].a22});
    int mid=l+r>>1;pushdown(p);
    return x<=mid?query(p<<1,l,mid,x):query(p<<1|1,mid+1,r,x);
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;for(int i=1;i<=n;i++)cin>>a[i],nums[a[i]].pb(i);
    for(int i=1;i<=n;i++){
        sz=nums[i].size();if(sz==0)continue;
        for(int j=0;j<sz;j++)res+=query(1,1,n,nums[i][j])+1;
        update(1,1,n,nums[i][0],n,{1,inf,inf,0,0});
        update(1,1,n,1,nums[i].back(),{0,inf,inf,1,0});
        update(1,1,n,1,nums[i].back(),{0,inf,0,0,0});
        update(1,1,n,nums[i][0],n,{0,0,inf,0,0});
    }cout<<res;
}

你可能感兴趣的:(学习,笔记,算法)