问题描述
小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到 n 的阶乘,并将结果存储在列表
fac
中。阶乘用于计算组合数。 - 计算好排列的数量:
- 如果 n 是偶数,偶数和奇数的数量相等,均为 n/2。此时,好排列的数量为 (n/2)!×(n/2)!×(n/2+1)。
- 如果 n 是奇数,偶数和奇数的数量相差1。此时,好排列的数量为 (n/2)!×(n−n/2)!。
- 取模运算:由于结果可能非常大,我们需要对结果取模 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;
}