2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛(重赛)Subpermutation

题意:把所有 n n n 元排列按字典序从小到大排成一列,求其中有多少长度为 m m m 的连续子串为 1 , 2 ⋯   , m 1, 2\cdots, m 1,2,m m m m 元排列,方案数模 1 e 9 + 7 1\rm e9+7 1e9+7 t t t 组询问, m < n m<n m<n n , m , t ≤ 1 × 1 0 6 n,m,t\leq 1\times 10^6 n,m,t1×106

解法:首先所有 m m m 元排列只有可能出现在两个排列中间或者独属于某一个 n n n 元排列。首先,独属于某一个 n n n 元排列方案数非常简单——在一个 n n n 元排列中选取一个长度为 m m m 的连续子串,位置共有 n − m + 1 n-m+1 nm+1 个,剩下数字直接排列即可,方案数为 ( n − m + 1 ) m ! ( n − m ) ! = m ! ( n − m + 1 ) ! \displaystyle (n-m+1)m!(n-m)!=m!(n-m+1)! (nm+1)m!(nm)!=m!(nm+1)!

下面考虑跨越两个 n n n 元排列的 m m m 元排列方案数。注意到排列的一个重要性质:假定当前排列为 p 1 , p 2 , ⋯   , p n p_1,p_2,\cdots, p_n p1,p2,,pn,且满足 ∃ k ∈ [ 1 , n − 1 ] \exist k\in[1,n-1] k[1,n1] ∀ i ∈ [ k + 1 , n − 1 ] , p i > p i + 1 \forall i\in [k+1,n-1],p_i>p_{i+1} i[k+1,n1],pi>pi+1,且 p k < p k + 1 p_k<p_{k+1} pk<pk+1,那么存在下一个排列,且该排列写作 p 1 , p 2 , ⋯   , p k − 1 , p j , p n , p n − 1 , ⋯   , p j + 1 , p k , p j − 1 , ⋯   , p k + 1 p_1,p_2,\cdots,p_{k-1},p_{j},p_{n},p_{n−1},\cdots, p_{j+1},p_{k},p_{j−1},\cdots,p_{k+1} p1,p2,,pk1,pj,pn,pn1,,pj+1,pk,pj1,,pk+1,其中 p j > p k p_j>p_k pj>pk 且是第一个大于 p k p_k pk 的数字。即当排列可以写作 p 1 , p 2 , ⋯   , p k < p k + 1 > p k + 2 > ⋯ > p n p_1,p_2,\cdots,p_k<p_{k+1}>p_{k+2}>\cdots>p_n p1,p2,,pk<pk+1>pk+2>>pn 时存在下一个排列,且会将后面一个次小的数字翻转到前面来。我们后面的分析会反复利用到这一性质。

记这样的下标 k k k 为折返点,考虑 k k k 可能的位置。又记当前的 m m m 元排列可以被分为前后两个 n n n 元排列的前后缀,其中后面一个排列的前缀长度为 i i i,则前半部分长度为 m − i m-i mi。同时考虑将当前的 m m m 元排列向前扩展到一个大小为 n n n 的范围。
在这里插入图片描述
大致可以分为这样的位置状态,下面会解释为什么一定是这样的。将 i i i k k k 的关系粗略分为以下两种——

  1. 折返点位于扩展点之后,大致位置如下所示:
    在这里插入图片描述
    或者如下这样:
    在这里插入图片描述
    只要折返点不在橙色区段,那么根据排列的性质,折返点前都不会受到影响,因而红色段和橙色段是完全一样的。那么为了让绿色段和红色段构成一个 m m m 元排列,大于 m m m 的剩下数字就只能放在蓝色段。因而,枚举前缀 i i i 的长度,则红色段方案数为 ( m i ) i ! \displaystyle {m\choose i}i! (im)i!,蓝色段方案数为 ( n − m ) ! (n-m)! (nm)!,绿色段由于数字在红色段选定,因而只有排列的方案也就是 ( m − i + 1 ) ! (m-i+1)! (mi+1)!。但是由于需要存在折返点,因而蓝色段和绿色段的总序列不可以是完全单调递减的,即扣去蓝色段单调递减和绿色段同时单调递减这一种情况,因而可以得到这部分的答案为 ∑ i = 1 m − 1 ( m i ) i ! ( ( n − m ) ! ( m − i + 1 ) ! − 1 ) \displaystyle \sum_{i=1}^{m-1} {m\choose i}i!((n-m)!(m-i+1)!-1) i=1m1(im)i!((nm)!(mi+1)!1)。打开组合数,容易得到方案数为 ( m − 1 ) m ! ( n − m ) ! − m ! ∑ i = 1 m − 1 1 i ! \displaystyle (m-1)m!(n-m)!-m!\sum_{i=1}^{m-1}\frac{1}{i!} (m1)m!(nm)!m!i=1m1i!1

  2. 折返点位于前缀部分(橙色)
    在这里插入图片描述
    这种情况其实是不存在的。显然,紫线前的和红色段中对应紫线位置之前的地方都是不变的。考虑当前要交换到前面来的元素—— p j p_j pj,如果这个 p j p_j pj 位于绿色段,那么这个 p j p_j pj 就会调换到红色区段来,发生重复;那么调换位置必然位于蓝色段。同时,被交换的第一个数——即紫色段右侧的第一个数,势必会被交换到后面的某一个地方。那么,无论如何要么是绿色段的一个值进入了红色段,要么是橙色部分的值没有进入红色段,始终会让红色段的数字集合与橙色段的不同(由于绿色段是共用的,因而橙色段必须和红色段数字集合相同),从而发生冲突。因而这部分答案为 0 0 0

因而总答案为 m ! ( n − m + 1 ) ! + ( m − 1 ) m ! ( n − m ) ! − m ! ∑ i = 1 m − 1 1 i ! \displaystyle m!(n-m+1)!+(m-1)m!(n-m)!-m!\sum_{i=1}^{m-1}\dfrac{1}{i!} m!(nm+1)!+(m1)m!(nm)!m!i=1m1i!1,经过预处理可以 O ( 1 ) O(1) O(1) 的计算。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值