「NNEZ Monthly Round 6」LIS

20分

首先考虑Ai>0A_i>0的情况

显然有dp方程:

fi=max1j<i{fj+1}(Aj<Ai)f_i=max_{1\le j<i}\{f_j+1\}(A_j<A_i)

边界条件f[i]=1f[i]=1

时间复杂度O(n2)O(n^2),期望得分20分

50分

50分(100分)的数据要求我们在O(nlogn)O(n\log n)的时间复杂度内解决这个问题

定义序列DiD_i表示对于所有满足fk=if_k=ikk中,AkA_k最小是多少

Di=minfk=i{Ak}D_i=min_{f_k=i}\{A_k\}

显然序列DD是单调递增的(想一想,为什么)

我们来考虑如何维护这个序列DD

假设当前序列DD的长度为lenlen,当前扫描到的元素为AiA_i,分两种情况:

  1. 如果Ai>DlenA_i>D_{len},那么令Dlen+1=AiD_{len+1}=A_i,同时令len=len+1len=len+1,意义为将AiA_i接到以DlenD_{len}为结尾的上升子序列后面
  2. 如果AiDlenA_i\le D_{len},那么在序列DD二分找到第一个pp满足DpAiD_p\ge A_i,令Dp=AiD_p=A_i,意义为把以DpD_p为结尾的上升子序列的末尾元素(即DpD_p)换成AiA_i

tips:
lowerbound(D+1,D+len+1,x)-D
可以得到DD数组中第一个大于等于xx的位置是第几个

我们来思考一下第二种情况的意义,对于一个上升子序列,我们自然希望在它后面能接更多的元素,那么这个子序列的末尾元素当然是越小越好

扫描完整个序列AA后,LIS的长度即为序列DD的长度lenlen

时间复杂度O(nlogn)O(n\log n),至此期望得分50分

100分

考虑AiA_i可能会等于0的情况

首先,对于一个末尾为XX的上升子序列,如果我们既可以在它后面接一个00,也可以接一个AiA_i(即Ai>XA_i>X),那么显然接00一定不会使答案更劣

所以一个包含AiA_i中所有00的上升子序列,一定不会比最长上升子序列短

那么我们可以先把所有的00塞进答案子序列里,然后再塞非零的元素

对于剩下的非零元素,我们先考虑其中两个元素Ai,Aj(i<j)A_i,A_j(i<j),设它们之间00的个数为kk

由于我们必须要保证上升子序列中的元素严格递增,并且要保证已经塞进上升子序列中的00能够指派一个值,所以如果AiA_iAjA_j能够被同时塞进答案子序列里,必须要满足:

Ai+k<AjA_i+k<A_j

我们定义一个函数g(i)g(i)表示位置ii前面00的个数,定义Bi=Aig(i)B_i=A_i-g(i)

那么我们可以塞进答案子序列里的非零元素个数即为序列BB的LIS长度

证明:
对于任意i,ji,j满足i<ji<j

Bi<BjAig(i)<Ajg(j)Ai+[g(j)g(i)]<AjAi+k<AjB_i<B_j\\ \Leftrightarrow A_i-g(i)<A_j-g(j)\\ \Leftrightarrow A_i+[g(j)-g(i)]<A_j\\ \Leftrightarrow A_i+k<A_j

最终的答案是序列BB的LIS长度加上序列AA00的个数

二分求LIS,期望得分100分

需要注意的是,由于我们已经提前考虑了00,所以在计算序列BB的LIS长度时,需要跳过Ai=0A_i=0的位置

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
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn=100005;

int n;
int a[maxn];
int d[maxn],len;

int main()
{
scanf("%d",&n);
int zero=0;
d[0]=-0x7f7f7f7f;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
if(a[i]==0)
++zero;
else
{
a[i]-=zero;
if(a[i]>d[len])
d[++len]=a[i];
else
{
int p=lower_bound(d+1,d+len+1,a[i])-d;
d[p]=a[i];
}
}
}
printf("%d",len+zero);
}

谢罪

之前月赛讲题的时候,条理不甚清晰,错漏诸多,所以特地重新写了一篇自认为相对更加详细严谨的题解

非常抱歉,我什么都会做的(土下座)