好排列的数量计算

问题描述

        小R正在研究一种特殊的排列,称为“好排列”。一个排列被称为“好排列”,当且仅当其中所有相邻的两个数的乘积均为偶数。现在给定一个正整数 n,小R想知道,长度为 n 的好排列共有多少种。由于结果可能非常大,你需要将结果对 10^9+7取模后输出。


测试样例

样例1:

输入:n = 2
输出:2

样例2:

输入:n = 3
输出:2

样例3:

输入:n = 5
输出:12

Python实现

思路说明

        题目要求计算长度为 n 的好排列的数量,其中好排列的定义是所有相邻的两个数的乘积均为偶数。首先,我们需要理解偶数乘积的条件:两个数中至少有一个是偶数。因此,好排列中的所有数必须是偶数或者奇数交替排列。

        对于长度为 n 的排列,我们可以将其分为两部分:偶数和奇数。如果 n 是偶数,那么偶数和奇数的数量相等;如果 n 是奇数,那么偶数和奇数的数量相差1。我们可以通过计算组合数来确定好排列的数量。

解题过程

  1. 计算阶乘:首先,我们计算从1到 n 的阶乘,并将结果存储在列表 fac 中。阶乘用于计算组合数。
  2. 计算好排列的数量
    • 如果 n 是偶数,偶数和奇数的数量相等,均为 n/2。此时,好排列的数量为 (n/2)!×(n/2)!×(n/2+1)。
    • 如果 n 是奇数,偶数和奇数的数量相差1。此时,好排列的数量为 (n/2)!×(n−n/2)!。
  3. 取模运算:由于结果可能非常大,我们需要对结果取模 10^9+7。

复杂度分析

  • 时间复杂度:计算阶乘的时间复杂度为 O(n),计算好排列数量的时间复杂度为 O(1)。因此,总的时间复杂度为 O(n)。
  • 空间复杂度:我们使用了一个列表 fac 来存储阶乘结果,空间复杂度为 O(n)。

知识点扩展

  • 排列组合:题目涉及排列组合的基本概念,特别是阶乘的计算和组合数的应用。
  • 数学推理:通过分析偶数和奇数的排列方式,推导出好排列的数量公式。
  • 取模运算:在处理大数问题时,取模运算可以避免溢出,并确保结果在合理范围内。

代码实现

def solution(n:int) -> int:
    mod = 10 ** 9 + 7
    fac = [1]
    for i in range(1, n + 1):
        fac.append(fac[-1] * i % mod)
    if n % 2 == 0:
        ans = fac[n // 2] ** 2 * (n // 2 + 1) % mod
    else:
        ans = fac[n // 2] * fac[n - n // 2] % mod
    return ans

if __name__ == '__main__':
    print(solution(n = 2) == 2)
    print(solution(n = 3) == 2)
    print(solution(n = 5) == 12)

C++实现

代码实现

#include <iostream>
#include <vector>

const long long MOD = 1000000007;

// 计算阶乘的函数
long long factorial(int n) {
    long long result = 1;
    for (int i = 1; i <= n; ++i) {
        result = (result * i) % MOD;
    }
    return result;
}

int solution(int n) {
    std::vector<long long> fac(n + 1, 1);
    for (int i = 1; i <= n; ++i) {
        fac[i] = (fac[i - 1] * i) % MOD;
    }
    
    long long ans;
    if (n % 2 == 0) {
        ans = (fac[n / 2] * fac[n / 2] % MOD) * (n / 2 + 1) % MOD;
    } else {
        ans = (fac[n / 2] * fac[n - n / 2] % MOD);
    }
    return ans;
}

int main() {
    std::cout << (solution(2) == 2) << std::endl;
    std::cout << (solution(3) == 2) << std::endl;
    std::cout << (solution(5) == 12) << std::endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值