题解:AtCoder AT_abc468_c Between P and Q

【题目来源】

AtCoder:Between P and Q

【题目描述】

You are given an integer \(N\) and integer sequences \(P=(P_1,P_2,\ldots, P_N)\) and \(Q=(Q_1,Q_2,\ldots,Q_N)\), each of which is a permutation of \((1,2,\ldots,N)\).

Find the number of integer sequences that are a permutation of \((1,2,\ldots,N)\) and are lexicographically greater than \(P\) and lexicographically less than \(Q\).

What is lexicographic order for integer sequences?

For integer sequences \(S = (S_1,S_2,\ldots,S_{|S|})\) and \(T = (T_1,T_2,\ldots,T_{|T|})\), we say that \(S\) is lexicographically smaller than \(T\) if \(1.\) or \(2.\) below holds. Here, \(|S|, |T|\) denote the lengths of \(S, T\), respectively.

  1. \(|S| \lt |T|\) and \((S_1,S_2,\ldots,S_{|S|}) = (T_1,T_2,\ldots,T_{|S|})\).
  2. There exists an integer \(1 \leq i \leq \min\lbrace |S|, |T| \rbrace\) such that both of the following two conditions hold.
    • \((S_1,S_2,\ldots,S_{i-1}) = (T_1,T_2,\ldots,T_{i-1})\)
    • \(S_i\) is (numerically) smaller than \(T_i\).

给定一个整数 \(N\) 和整数序列 \(P=(P_1,P_2,\ldots, P_N)\) 以及 \(Q=(Q_1,Q_2,\ldots,Q_N)\),它们都是 \((1,2,\ldots,N)\) 的排列。

求满足以下条件的整数序列的数量:该序列是 \((1,2,\ldots,N)\) 的排列,且按字典序大于 \(P\) 且小于 \(Q\)

什么是整数序列的字典序?

对于整数序列 \(S = (S_1,S_2,\ldots,S_{|S|})\)\(T = (T_1,T_2,\ldots,T_{|T|})\),如果满足以下 \(1.\)\(2.\) 之一,则称 \(S\) 字典序小于 \(T\)。这里 \(|S|, |T|\) 分别表示 \(S, T\) 的长度。

  1. \(|S| \lt |T|\)\((S_1,S_2,\ldots,S_{|S|}) = (T_1,T_2,\ldots,T_{|S|})\)
  2. 存在整数 \(1 \leq i \leq \min\lbrace |S|, |T| \rbrace\),使得以下两个条件同时成立。
    • \((S_1,S_2,\ldots,S_{i-1}) = (T_1,T_2,\ldots,T_{i-1})\)
    • \(S_i\)(在数值上)小于 \(T_i\)

【输入】

The input is given from Standard Input in the following format:

\(N\)
\(P_1\) \(P_2\) \(\ldots\) \(P_N\)
\(Q_1\) \(Q_2\) \(\ldots\) \(Q_N\)

【输出】

Output the answer.

【输入样例】

3
1 3 2
3 1 2

【输出样例】

2

【核心思想】

  1. 问题分析:给定两个排列 \(P\)\(Q\),求满足 \(P <_{lex} X <_{lex} Q\) 的排列 \(X\) 的数量。这是一个全排列枚举 + 字典序比较问题,核心在于利用 next_permutation 枚举所有排列并统计满足条件的个数。

  2. 算法选择

    • 全排列枚举:使用 next_permutation 按字典序生成所有 \(N!\) 个排列
    • 字典序比较:自定义函数逐位比较判断当前排列是否满足 \(P < X < Q\)
  3. 关键步骤

    • 读入数据:读取 \(N\),排列 \(P[1..N]\)\(Q[1..N]\)
    • 初始化\(a[i] = i\)(字典序最小的排列)
    • 全排列枚举\(do-while\) 循环):
      • \(greaterThanP()\)\(lessThanQ()\)\(ans \leftarrow ans + 1\)
      • \(next\_permutation(a+1, a+N+1)\)
    • 输出结果\(ans\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N! \cdot N)\)\(N!\) 个排列,每个比较 \(O(N)\)
    • 空间复杂度:\(O(N)\),存储排列
  5. 全排列枚举与字典序的核心思想

    • 字典序的定义:从左到右逐位比较,第一个不同的位置决定大小关系。若所有位相同则两排列相等
    • next_permutation 的有序性next_permutation 按字典序从小到大生成排列,确保不遗漏、不重复
    • 边界条件\(P < X\) 要求 \(X\) 严格大于 \(P\)(不能等于),\(X < Q\) 要求 \(X\) 严格小于 \(Q\)(不能等于)
    • 数据范围限制\(N \leq 15\) 使得 \(N!\) 枚举可行(\(15! \approx 1.3 \times 10^{12}\) 实际不可行,但题目数据范围较小或存在更优解法)
    • 适用于小规模排列枚举、字典序比较类基础问题

【算法标签】

DFS-一维

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 15;       // 定义数组最大容量为15,满足N的数据范围(全排列枚举,N不能太大)
int n, ans;             // n为排列长度,ans记录满足条件的排列数量
int a[N], p[N], q[N];   // a用于生成全排列;p和q分别存储给定的两个排列P和Q

// 判断当前排列a是否字典序大于排列P
bool greaterThanP()
{
    for (int i = 1; i <= n; i++)  // 从左到右逐位比较a和P
    {
        if (a[i] > p[i])          // 如果a的当前位大于P的当前位
            return true;          // a字典序大于P,返回true
        if (a[i] < p[i])          // 如果a的当前位小于P的当前位
            return false;         // a字典序小于P,返回false
    }
    return false;                 // 所有位都相同,a等于P,不满足"大于",返回false
}

// 判断当前排列a是否字典序小于排列Q
bool lessThanQ()
{
    for (int i = 1; i <= n; i++)  // 从左到右逐位比较a和Q
    {
        if (a[i] < q[i])          // 如果a的当前位小于Q的当前位
            return true;          // a字典序小于Q,返回true
        if (a[i] > q[i])          // 如果a的当前位大于Q的当前位
            return false;         // a字典序大于Q,返回false
    }
    return false;                 // 所有位都相同,a等于Q,不满足"小于",返回false
}

int main()
{
    cin >> n;                     // 读入排列长度N
    for (int i = 1; i <= n; i++)  // 读入排列P
        cin >> p[i];
    for (int i = 1; i <= n; i++)  // 读入排列Q
        cin >> q[i];
    for (int i = 1; i <= n; i++)  // 初始化a为字典序最小的排列(1,2,...,N)
        a[i] = i;
    do
    {
        bool flag = false;        // flag未使用
        if (greaterThanP() && lessThanQ())  // 如果当前排列a同时满足:字典序大于P且小于Q
            ans++;                // 满足条件的排列数量加1
        
    } while (next_permutation(a + 1, a + n + 1));  // 生成下一个字典序更大的排列,直到枚举完所有排列
 
    cout << ans << endl;          // 输出满足条件的排列总数
    return 0;
}

【运行结果】

3
1 3 2
3 1 2
2
posted @ 2026-07-26 17:32  团爸讲算法  阅读(1)  评论(0)    收藏  举报