题目链接 琪亚娜世界第一可爱
给出长度为n的以一个数组,数组中的元素最大不超过x。现在你可以执行一个操作 f(l,r),将数组中所有大于等于l且小于等于r的元素都删除,现在求有多少种方案可以使执行完这个操作后的数组为非减顺序
首先因为空串被认为是符合的,所以f(1,x)是一定可行,并由此推得f(1,x-1)也是一定可行的。所以我们可以从后向前推,直到出现第一个不符合要求的f(1,min_suffix),这样以1开始的所有符合要求的操作就是f(1,min_suffix…x)。
之后我们再考虑以2开始的操作,同样f(2,x)也是一定可行,之后再向后判断,找出f(2,min_suffix)。
从3开始时我们就要判断其成立条件,也就是说f(3,x)是不一定可行的,因为{1,2}的顺序不定,所以要先判断1与2的位置关系,再找到f(3,min_suffix)
这样重复起始位置的增加,直到以n+1开始,{1,2…n}在原序列中的顺序不符合要求,所以在n+1以后包括n+1的操作就都不用再考虑了。
而在上述过程中,min_suffix是固定的,且min_suffix+1就是原序列中最长非递减后缀的起始位置上的元素值。n-1则是原序列中最长非递减前缀的结束位置上的元素值
所以现在问题转换为对于元素值i来说,求最小的cur_lim使得f(i,cur_lim)成立。首先要确保操作后没有比 i-1 大的数出现在 i-1 前面,故要删除到 最后一个 i-1 出现前的最大值 before_max[i-1] ;其次,还要至少删到min_suffix,所有取这两个数的最大值。因为i一定在非递减前缀中,所以可以用before_max[i]来替代before_max[i-1]。
再来看一下上下边界
- 当 i==1 时
这是我们只需要删到min_suffix而不用关心在1前的最大值 - 当 i==n 时
这是n不在非递减前缀中,而是这个前缀中最大值+1 。虽然它不在前缀中,但是可以有操作使结果非递减,也是唯一一个特殊的位置。最后的结果是 完整的最长非递减前缀 + 最长非递减后缀 。所以在这里我们要取 max(before_max[1],min_suffix)为cur_lim,为的是让这个前缀的第一个元素成立。
这样我们就处理完了所有出现过的元素,而对于没出现过的元素,我们并不能跳过,也要记入答案中。记这个值为val,由于val没有出现过,所以before_max没有关于val的记录,所以取上一次出现过的元素的cur_lim为参数, 取max(cur_lim,i)为cur_lim 。
#pragma GCC diagnostic error "-std=c++11"
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return
#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
const int maxn=1e6+5;
int N,x;
int store[maxn];
int first_pos[maxn],last_pos[maxn],max_before[maxn];
map<int,bool> appear;
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
int m=-1;
cin>>N>>x;
rep(i,1,N+1){
cin>>store[i];
int &num=store[i];
if(!appear[num]){
appear[num]=true;
first_pos[num]=i;
}
last_pos[num]=i;
m=max(m,num);
max_before[num]=m;
}
first_pos[x+1]=maxn;
int min_suffix=1,pos=maxn;
drep(i,x,1){
if(!first_pos[i])
continue;
if(last_pos[i]>pos){
min_suffix=i;
break;
}
pos=min(pos,first_pos[i]);
}
pos=last_pos[1];
int cur_lim=max(min_suffix,max_before[1]);
ll ans=x-min_suffix+1;
rep(i,2,x+1){
if(!first_pos[i]){
ans+=x-max(cur_lim,i)+1;
continue;
}
if(pos>first_pos[i]){
ans+=x-max(min_suffix,max_before[1])+1;
break;
}
cur_lim=max(cur_lim,max_before[i]);
ans+=x-cur_lim+1;
pos=max(pos,last_pos[i]);
}
cout<<ans<<endl;
re 0;
}