GYM-100553I
in zh-CH

题意简述

原题说的是鬼话,这里是人话转述:

n+1n+1 个点 x0,x1,,xnx_0,x_1,\dots,x_n 其中 x0=0x_0=0xix_i 两两不同且 1xin1\le x_i\le n ,视第 ii 个区间为 (xi1,xi)(x_{i-1},x_i) ,定义 A,BA,B 两区间不相交为 ABϕ,A⊈BB⊈AA\cap B \ne\phi,A\not\subseteq B,B\not\subseteq A。要使没有区间相交,有一些 xix_i 要改变,求出不用改变的 xix_i 最多有几个。

1n2×1051\le n\le 2\times 10^5

题解

没有区间相交,就是说任意一对区间要么包含要么交集为空。

仔细想想,可以发现,若最终 nn 个区间合法,对于 i<ji\lt j ,第 jj 个区间不能包含第 ii 个区间。

手画一下图可以反证若包含一定是不合法的。

然后每一个区间都 要么被之前包含要么于之前交集为空。随着 ii 的增加,区间能取到的左端点一定是单调不减的,同理能取到的右端点一定是单调不增的。

p[xi]=ip[x_i]=i ,可以发现 pp 先增后减,于是只要枚举 pp 从中间某切开,向左最长单调下降子序列+向右最长单调下降子序列-1 更新答案即可,于是变成了简单dp,有手就行

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <bits/stdc++.h>
#define _max(x,y) ((x>y)?x:y)
#define _min(x,y) ((x<y)?x:y)
#define re register
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
template<typename T>
inline void red(T &x) {
x=0;bool fg=0;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') fg^=1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(T)(ch^48),ch=getchar();
if(fg) x=-x;
}
template<typename T> bool umax(T &x,T y) {return (x<y)?(x=y,true):(false);}
template<typename T> bool umin(T &x,T y) {return (x>y)?(x=y,true):(false);}
const int N = 200010;
int p[N],n,L[N],R[N];
struct trearr {
int t[N];
void modify(int x,int vl) {for(;x<=n;x+=x&-x) umax(t[x],vl);}
int ask(int x) {int r=0;for(;x>0;x-=x&-x) umax(r,t[x]);return r;}
}f1,f2;
// L[i] 向左的最长下降子序列,R[i] 向右
int main() {
freopen("improvements.in","r",stdin);
freopen("improvements.out","w",stdout);
red(n);
for(int i=1;i<=n;i++) {
int x;red(x);
p[x]=i;
}
for(int i=1;i<=n;i++) {
L[i]=f1.ask(p[i]-1)+1;
f1.modify(p[i],L[i]);
}
for(int i=n;i>=1;i--) {
R[i]=f2.ask(p[i]-1)+1;
f2.modify(p[i],R[i]);
}
int ans=0;
for(int i=1;i<=n;i++) umax(ans,L[i]+R[i]-1);
printf("%d\n",ans);
return 0;
}