千年大坑。
合法排列有什么性质
首先考虑排列如何达到交换下界。
单独的考虑排列中的一个数,对于其目标位置,容易发现每一次关于这个数的交换一定是朝着目标位置的方向换的。对于排列 2,1 ,2 要到后面 1 要到前面,所以交换不会浪费次数。但是如果在前面加上 3 ,3 要到后面去,2 位置不变,1 要到前面去。
3 往后面去的时候 2 会往前走,1 往前面去的时候 2 又被搬回来,这样就浪费了交换次数。考虑一般情况,即排列中有 ai,aj,ak 满足 i<j<k,ai>aj>ak ,最终情况下 ai 一定是要到 ak 的后面的,ak 也一定是要到 ai 的前面,两者方向不同,中间的 aj 就会浪费交换次数。
所以如果当排列中出现了长度为 3 甚至以上的子序列,并且满足子序列递减,那么排列不合法。
容易发现长度为 2 甚至以下的递减子序列和其他递增子序列都不会浪费交换次数。
简单情况如何统计
首先考虑 pi=i ,也就是忽略字典序顺序。
设 dp(i,j) 表示选了 i 个数,最大值为 j 的方案数。转移显然要么选一个更大的,要么选小于 j 的数中最小的。
令小于 j 的数中最小的数为 a ,如果选了一个小于 j 的数 b 但 a<b ,因为 a 无论如何都要加入,也就只能以后加入,这样就形成了由 j,b,a 组成的递减子序列。
转移式即:
dp(i,j)=j∑k=i−1dp(i−1,k)
时间复杂度 O(n2) 。
如何快速求出 dp 数组
观察 dp 数组的转移式,会发现 dp(i,j)=dp(i−1,j)+dp(i,j−1) 。
考虑将 dp 搬到二维平面上,用点 (i,j) 表示 dp(i,j) 。每一次转移就是往前走一步或者往上走一步。但是不能出现 j>i 的情况,转而言之就是不能越过 y=x 这条直线,也就是不能触碰 y=x−1 这条直线。
这是一个经典的套路:首先令按照上述方式走,没有直线限制走到点 (i,j) 的方案数为 f(i,j) 。
那么 dp(i,j) 就是 f(i,j) 减去非法情况。考虑将第一次触碰直线 y=x−1 的点后面的路径按照直线 y=x−1 翻转,也就是终点变成了 (j+1,i−1) ,这样就可以得到:
dp(i,j)=f(i,j)−f(j+1,i−1)
现在考虑 f(i,j) 如何求。
可以往左走也可以往上走,显而易见的有:
f(i,j)=(i+ji)
时间复杂度 O(1) ,预处理要 O(n) 。
对于另外一种处理 dp 数组的想法
按照原来的 dp 转移式子,同样放到二维平面来考虑。
直线的限制是一样的,同样的设没有直线限制走到点 (i,j) 的方案数为 g(i,j) 。现在需要考虑 g(i,j) 如何求。
现在一共是走了 i 步,然后每一步的步长总和为 j,步长可以为 0 。可以转化为一共 i 个盒子,j 个小球,可以空盒子的方案数。于是就可以得到:
g(i,j)=(i+j−1i−1)
需要注意的是,由于在这种情况下只能” 横着走”,即每一步 i 必须加 1 。从 (0,0) 到 (j+1,i−1) 的” 竖着走” 的方案数。对应过来就是到 (i−1,j+1) 的” 横着走” 的方案数。
(不会玩,暂时留坑
字典序问题如何处理
(不知道为啥卡这卡好久 …(于是开始钻研题解 ×
比较容易的一个方法就是枚举位置 i,前 i−1 个数都和 p 的对应位置相同,第 i 个数大于 pi ,然后将方案数加起来。
令 mx=maxi−1j=1pj,mi 为当前最小的可以填的数,讨论第 i 位的方案。
重新定义 dp :表示点 (i,j) 到 (n,n) 的方案数。
- 如果 pi=mi
- 填 mi 显然不合法。
- 填一个满足 mi<x<mx 的数 x,因为如果将 mi 留到后面就会形成 mx,x,mi,不合法。
- 填一个满足 x>mx 的数 x,方案数为 dp(i,mx+1) 。
- 如果 mi<pi<mx
- 只能填满足 x>mx 的数 x,方案数为 dp(i,mx+1) 。
- 当接下来处理 i+1 时,由于第 i 位填了 pi ,前面一定形成了 mx,pi,而还有小于 pi 的元素没有填,接下来一定不存在合法方案了。
- 如果 pi≥mx
- 填一个满足 x>pi 的数 x,方案数为 dp(i,pi+1) 。
时间复杂度 O(n) 。
0 条评论