首页 > 试题广场 >

小红的双生排列

[编程题]小红的双生排列
  • 热度指数:3655 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}小红定义一个排列是双生排列,当且仅当任意相邻两项之和均为奇数。
\hspace{15pt}现在小红想知道,长度为 n 的双生排列共有多少种?由于答案可能过大,请对 10^9+7 取模。

\hspace{15pt}长度为 n排列是由 1 \sim nn 个整数、按任意顺序组成的数组,其中每个整数恰好出现一次。例如,\{2,3,1,5,4\} 是一个长度为 5 的排列,而 \{1,2,2\}\{1,3,4\} 都不是排列,因为前者存在重复元素,后者包含了超出范围的数。

输入描述:
\hspace{15pt}输入一个整数 n \left(2 \leqq n \leqq 10^5\right) 代表排列的长度。


输出描述:
\hspace{15pt}输出一个整数,代表长度为 n 的双生排列数量对 10^9+7 取模的答案。
示例1

输入

3

输出

2

说明

\hspace{15pt}在这个样例中,长度为 3 的排列有:
\hspace{23pt}\bullet\, \{1,2,3\} 且为双生排列;
\hspace{23pt}\bullet\, \{1,3,2\}
\hspace{23pt}\bullet\, \{2,1,3\}
\hspace{23pt}\bullet\, \{2,3,1\}
\hspace{23pt}\bullet\, \{3,1,2\}
\hspace{23pt}\bullet\, \{3,2,1\} 且为双生排列。
package main

import "fmt"

const mod = 1000000007

// CountTwinPermutations 计算长度为n的双生排列数量
// 如果相邻的两项之和为奇数,说明必然是奇数和偶数相隔错开
// 利用排列组合的知识,依次对各个位置出现的可能性进行相乘,就能得到结果
func CountTwinPermutations(n int) int64 {
	if n < 2 {
		return 0
	}
	ans := int64(1)
	var even, odd int64
	if n%2 == 0 {
		// 如果n是偶数,那么奇数和偶数一样多
		// 可以是 奇数开始,也可以是偶数开始,所以结果要乘 2
		even = int64(n / 2)
		odd = even
		for even > 0 {
			ans = (ans * even) % mod
			even--
			ans = (ans * odd) % mod
			odd--
		}
		ans = (ans * 2)% mod
	} else {
		// 如果n是偶数,那么奇数必然要比偶数多一个
		// 而且必须以奇数开始(不然最后必然是两个偶数相加)
		even = int64(n / 2)
		odd = int64(n) - even
		for even > 0 {
			ans = (ans * even) % mod
			even--
			ans = (ans * odd) % mod
			odd--
		}
	}
	return ans
}

func main() {
	// 测试用例
	var n int
	fmt.Scan(&n)
	fmt.Println(CountTwinPermutations(n))
}

发表于 2025-04-07 11:57:51 回复(0)