CF1553(Div.1+Div.2) I 题解

前言

由于 NTT 是 10 10 10 级算法,所以本篇题解仅介绍到 O ( n 2 ) O(n^2) O(n2) 解法。

Description

给定一个长度为 n n n 的排列 p p p

令其中第 i i i 个位置的权值为最长的包含 i i i 的单调区间。例如, p = [ 4 , 1 , 2 , 3 , 7 , 6 , 5 ] p=[4,1,2,3,7,6,5] p=[4,1,2,3,7,6,5] 中,第 6 6 6 个位置的权值为 [ 5 , 7 ] [5,7] [5,7] 的长度,第 2 2 2 个位置的权值为 [ 2 , 4 ] [2,4] [2,4] 的长度。

将这些权值依次拼在一起,就得到了 p p p阶梯序列

给定 a a a,你需要求出存在多少个 p p p,使得 a a a p p p阶梯序列

1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105,时限 10s \texttt{10s} 10s,空限 1GB \texttt{1GB} 1GB

Solution

Part 1: 性质的分析与观察

根据阶梯序列的定义, a i a_i ai i i i 所属的极长单调区间长度。但是 i i i 既可以是这段区间的中间某个位置,也可以是两端的位置,考虑起来情况较多,较为困难。于是我们先考虑第一个位置,其只能作为单调区间的开头,思考起来较为容易。

x = a 1 x=a_1 x=a1。不难发现,此时 [ 1 , x ] [1,x] [1,x] 是一个极长单调区间。接下来,我们再考虑 p x + 1 p_{x+1} px+1,并令 x ′ = a x + 1 x'=a_{x+1} x=ax+1。不难发现, p x + 1 p_{x+1} px+1 不能与 [ 1 , x ] [1,x] [1,x] 合并成一个新的单调区间,且 [ x + 1 , x + x ′ ] [x+1,x+x'] [x+1,x+x] 也是一个极长的单调区间。以此类推,我们将序列划分为了若干个极长的单调区间。这样一来,我们就成功地将问题转化为:给定若干个区间,你需要往里面填数,使得序列构成一个排列,且每个给定的区间都是一个极长的单调区间,求方案数。

如果区间只要求单调,不要求极长,那么问题就十分简单了。由于每个区间的 p i p_i pi 在值域上都是连续的一段 [ L , R ] [L,R] [L,R],所以我们只需要钦定这些 [ L , R ] [L,R] [L,R] 的大小关系以及这些极长区间的增减性即可唯一确定 p p p。方案数不难通过组合数以及乘法原理写出。

若要求极长,问题变了复杂了起来。

注意到,若两段区间不可合并,那么限制会较为复杂;若必须合并,那么限制非常简单。这启发我们从反面考虑。但是,不可合并的相邻区间对太多了,这又启发我们容斥地计算。然而 n n n 较大,不能 2 n 2^n 2n 地枚举相邻对。

能否 dp \text{dp} dp 呢?

Part 2: dp 的设计与转移

为方便叙述,定义 s i s_i si 表示第 i i i 个区间的长度。

f i f_{i} fi 表示,仅考虑前 i i i 个区间的方案数。

根据容斥的基本思想,对于第 i + 1 i+1 i+1 个位置,它有两种选择:

  • violate the rule \text{violate the rule} violate the rule——它与前面的区间可以合并
  • follow the rule or not \text{follow the rule or not} follow the rule or not——无论它填什么都可以。

考虑动态地将第 i + 1 i+1 i+1 个区间插入进前 i i i 个区间的按值域左端点排序的序列。然而,无论对于前者(违反规则)还是后者(随意),插入的位置数似乎较难根据 i i i 直接确定(若插入到某个不恰当的位置,可能会将原来两个合并的区间断开)。

仔细分析——对于前者而言,若前面一个区间长度为 1 1 1,那么插入的位置有 2 2 2 个,否则只有 1 1 1 个;对于后者而言,令 j j j 为前 i i i 个区间中钦定可合并的次数,那么插入的位置树为 i − j + 1 i-j+1 ij+1 个。

从而,我们加维度 j j j,表示目前钦定合并的次数。同时,再加一维 k k k,表示上一个区间的长度是否为 1 1 1

总结一下最终的状态设计:令 f i , j , k f_{i,j,k} fi,j,k 表示,看了前 i i i 个区间,合并 j j j 次,上一个区间的长度为 1 1 1 或不为 1 1 1 的方案数。注意,这里的上一个区间长度不一定是 s i − 1 s_{i-1} si1,而可能是一个比它更大的值(因为 s i − 1 s_{i-1} si1 可能参与了多次合并,而使得上一个区间的长度较大)。

转移如下:

  • 钦定合并。
    f i − 1 , j , 0 → f i , j + 1 , 0 f_{i-1,j,0} \to f_{i,j+1,0} fi1,j,0fi,j+1,0 2 f i − 1 , j , 1 → f i , j + 1 , 0 2f_{i-1,j,1} \to f_{i,j+1,0} 2fi1,j,1fi,j+1,0

  • 钦定合并。

    • s i ≠ 1 s_i \neq 1 si=1,则
      2 ( i − j ) f i − 1 , j , 0 / 1 → f i , j , 0 2(i-j)f_{i-1,j,0/1} \to f_{i,j,0} 2(ij)fi1,j,0/1fi,j,0

    • s i = 1 s_i=1 si=1,则
      ( i − j ) f i − 1 , j , 0 / 1 → f i , j , 1 (i-j)f_{i-1,j,0/1} \to f_{i,j,1} (ij)fi1,j,0/1fi,j,1

这里容易出现一个错误,就是在转移的时候漏掉系数 2 2 2。由于长度超过 1 1 1 的区间的单调增与单调减是不同的,所以在向第三维为 0 0 0 的状态转移时,要额外乘上一个 2 2 2

边界:
①若 s 1 ≠ 1 s_1 \neq 1 s1=1 f 1 , 0 , 0 = 2 f_{1,0,0}=2 f1,0,0=2
②若 s 1 = 1 s_1=1 s1=1 f 1 , 0 , 1 = 1 f_{1,0,1}=1 f1,0,1=1
答案:

∑ i = 0 len ( − 1 ) i ( f n , i , 0 + f n , i , 1 ) \sum_{i=0}^{\text{len}} (-1)^i (f_{n,i,0}+f_{n,i,1}) i=0len(1)i(fn,i,0+fn,i,1)

时间复杂度 O ( n 2 ) O(n^2) O(n2)

//https://codeforces.ml/contest/1553/submission/123423493
for (int i=2;i<=len;i++){
    
    
	for (int j=0;j<=len;j++){
    
    
		chksum(f[i-1][j][0],f[i][j+1][0]);
		chksum(f[i-1][j][1],f[i][j+1][0],2);
		if (s[i]!=1){
    
    
			for (int k=0;k<2;k++)  chksum(f[i-1][j][k],f[i][j][0],2*(i-j));	
		}
		else{
    
    
			for (int k=0;k<2;k++)  chksum(f[i-1][j][k],f[i][j][1],i-j);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/119043415