1 条题解

  • 0
    @ 2025-10-28 11:38:34

    核心思路

    1. 好排列的等价条件

    经过推导(原题提示),好排列等价于没有长度 3\ge 3 的下降子序列的排列。

    这进一步等价于排列能拆分成至多两个递增子序列


    2. 组合表示

    这样的排列可以用 Catalan 数的某种扩展来计数。

    对于长度为 nn 的排列,能拆分成两个递增子序列的排列个数就是 Catalan 数 CnC_nn!n! 倍?不,实际上就是 CnC_n 相关的某种结构。

    更准确地说,这类排列与 Ballot 序列Dyck 路径 双射。


    3. 代码中的关键函数

    int F(int x, int y) {
        return x <= y && y <= n ? 
            (C(2 * n - x - y - 1, n - x - 1) - 
             C(2 * n - x - y - 1, n - y - 2) + mod) % mod : 0;
    }
    

    这个 F(x, y) 函数计算的是:

    • 在网格图中从 (x,y)(x, y)(n,n)(n, n),且不穿过对角线 y=xy = x 的路径数
    • 这对应着好排列的某种计数

    4. 算法流程

    1. 预处理阶乘和逆元,用于组合数计算
    2. 对每个测试用例:
      • 读入排列 a[1..n]a[1..n]
      • 计算前缀最大值 mx[i]
      • 计算后缀最小值 mn[i]
    3. 逐位确定
      • 对于位置 ii,假设前 i1i-1 位与 qq 相同,第 ii 位选择比 q[i]q[i] 大的数
      • F(i-1, mx[i]+1) 计算这种情况下剩余位置能形成好排列的方案数
      • 累加到答案
    4. 提前终止
      • 如果发现 mx[i-1] > a[i] && a[i] > mn[i+1],说明后续无论如何都会破坏好排列条件,直接退出

    关键点解释

    为什么 F(i-1, mx[i]+1) 能计数?

    • i-1 表示已经确定了前 i1i-1 个位置
    • mx[i]+1 表示第 ii 位至少要选的最小值(为了字典序大于 qq
    • F(x,y) 计算的是从状态 (x,y)(x,y) 出发能形成好排列的方案数

    提前终止条件

    if (mx[i-1] > a[i] && a[i] > mn[i+1])
        break;
    

    这个条件检测是否出现了「长度 3\ge 3 的下降子序列」:

    • mx[i-1] 是前缀最大值
    • a[i] 是当前值
    • mn[i+1] 是后缀最小值 如果 mx[i-1] > a[i] > mn[i+1],那么 (mx[i-1], a[i], mn[i+1]) 就构成了长度为 3 的下降子序列,后续无论如何都不能形成好排列。

    举例验证

    对于样例:

    n=3, a=[1,3,2]
    

    计算过程:

    • i=1: F(0,2) = 计算从(0,2)到(3,3)的合法路径数
    • i=2: F(1,4) = 0(y>n)
    • i=3: 不计算,因为前两位已经确定

    最终得到答案 3。


    时间复杂度

    • 预处理阶乘:O(N)O(N)
    • 每个测试用例:O(n)O(n)
    • 总复杂度:O(n)O(\sum n),可以通过 n6×105n \le 6\times 10^5 的数据

    总结

    这道题的核心是将「好排列」的组合结构转化为网格路径计数问题,然后利用字典序逐位确定的方法统计方案数。代码中的 F(x,y) 函数是关键,它用组合数相减的方法计算了不穿过对角线的路径数,这正好对应了好排列的计数。

    • 1

    信息

    ID
    4446
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    5
    已通过
    1
    上传者