1 条题解

  • 0
    @ 2025-10-16 22:11:05

    这是一个组合数学问题,需要计算从 n 本书中选 m 本,且任意两本不相邻的选法数。

    数学推导: 设选中的书位置为 a1,a2,...,ama_1, a_2, ..., a_m,满足:

    • 1a1<a2<<amn1 \leq a_1 < a_2 < \cdots < a_m \leq n
    • ai+1ai2a_{i+1} - a_i \geq 2(不相邻)

    我们可以通过插空法来求解:

    1. 先选出 m 本书
    2. 在选中的 m 本书之间插入间隔,确保不相邻

    bi=ai(i1)b_i = a_i - (i-1),则 b1<b2<<bmb_1 < b_2 < \cdots < b_m1b1<b2<<bmnm+11 \leq b_1 < b_2 < \cdots < b_m \leq n-m+1

    因此,问题转化为从 nm+1n-m+1 个元素中选 m 个的组合数。

    公式: C(nm+1,m)C(n-m+1, m)

    边界条件:

    • 如果 m=0m = 0,只有 1 种选法(什么都不选)
    • 如果 nm+1<mn-m+1 < mnm+1<0n-m+1 < 0,无解
    #include <iostream>
    using namespace std;
    
    // 计算组合数 C(a, b)
    long long comb(int a, int b) {
        if (b < 0 || b > a) return 0;
        if (b == 0 || b == a) return 1;
        
        long long res = 1;
        // 使用递推公式 C(a,b) = C(a,b-1) * (a-b+1) / b
        for (int i = 1; i <= b; i++) {
            res = res * (a - i + 1) / i;
        }
        return res;
    }
    
    int main() {
        int n, m;
        cin >> n >> m;
        
        // 特殊情况处理
        if (m == 0) {
            cout << 1 << endl;
            return 0;
        }
        
        if (n - m + 1 < m || n - m + 1 < 0) {
            cout << "No Answer" << endl;
            return 0;
        }
        
        long long result = comb(n - m + 1, m);
        
        if (result == 0) {
            cout << "No Answer" << endl;
        } else {
            cout << result << endl;
        }
        
        return 0;
    }
    

    测试样例:

    样例1:

    输入:3 2
    计算:C(3-2+1, 2) = C(2, 2) = 1
    输出:1
    

    样例2:

    输入:3 3
    计算:C(3-3+1, 3) = C(1, 3) = 0
    输出:No Answer
    

    算法复杂度: O(min(m, n-m)),非常高效。

    关键点:

    1. 不相邻选择问题转化为组合数问题
    2. 注意边界条件和无解情况的判断
    3. 使用递推公式计算组合数,避免溢出

    信息

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