题意:删除原数组中值域为[ 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
*/