输入一个整数
代表排列的长度。
输出一个整数,代表长度为
的双生排列数量对
取模的答案。
3
2
在这个样例中,长度为
的排列有:
![]()
且为双生排列;
![]()
;
![]()
;
![]()
;
![]()
;
![]()
且为双生排列。
主要考察防止数值溢出的取模知识,本题为排列知识,例如当n = 4(偶数)时,1,2,3,4。
此时奇偶数相等,数量均为n / 2。第一步可以放奇或偶数。若放奇数,选择有两个(1或3)。
第二个需放偶数,选择有两个(2或4);第三个放奇数,由于前面放了一个奇数,故现在只剩下一个奇数。
把各步能选择的个数相乘即可得到答案。但第一步也可以放偶数,所以答案要×2。
但当n = 3(奇数)时:1、2、3,第一步只能放奇数,否则2,1,3不满足题意。所以最后的答案不需要×2。
过程中需要注意乘数溢出问题,每一次乘法都需要对mod取模。
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int totalNums = in.nextInt();
long mod = 1000000007;
if (totalNums % 2 == 0){
int OuShuEqualsQiShu = totalNums / 2;
long res = 1;
for (int i = 2; i <= OuShuEqualsQiShu; i++){
res = res * i % mod;
}
System.out.println((res * res * 2) % mod);
}else{
int ouShu = totalNums / 2;
long res = 1;
for (int i = 2; i <= ouShu; i++){
res = res * i % mod;
}
System.out.println(((res * res) % mod * (ouShu + 1)) % mod);
}
}
}
} #include <bits/stdc++.h>
using namespace std;
using ll = long long ;
ll ans = 0;
void Judge(int ou,int ji){
ll sum = 1;
int flag=0;
if(ji==ou) flag = 1;
do{
sum*=ou;
sum = sum%1000000007;
}while(--ou);
do{
sum*=ji;
sum = sum%1000000007;
}while(--ji);
if(flag == 1){
ans = sum*2%1000000007;
return;
}
ans = sum%1000000007;
}
int main() {
int n;
cin>>n;
if((n&0x1)==0){
Judge(n/2,n/2);
}
else{
Judge((n-1)/2,(n+1)/2);
}
cout<<ans;
} #排列组合问题,奇偶分开排列 #N为奇数,奇数只能放在前面,所以直接奇数的排列乘以偶数的排列就是答案 #N为偶数时,奇偶都可以放在前面,所以答案等于上面的情况乘以2 #这里取模比较麻烦不能自己写阶乘函数了,用math库里的函数直接输出阶乘取模 #乘法的取模算法可以去网上搜一下 import math n = int(input()) #计算奇偶数的数量 if n%2 == 0: qishu_c = n//2 oushu_c = n//2 else: qishu_c = n//2 + 1 oushu_c = n//2 #这里答案应该是n为奇数时,阶乘一(qishu_c)乘上阶乘二 (oushu_c);N为偶数时,乘二就可以了 #这里答案过于大,进行乘法的取模操作 M = 10**9+7 res1 = math.factorial(qishu_c)%M res2 = math.factorial(oushu_c)%M if n % 2 == 0: res = res1 * res2 % M print((res*2)%M) else: res = res1 * res2 % M print(res)
#include <iostream>
#include <cmath>
using namespace std;
const long long MOD = 1e9 + 7;
// 递归计算阶乘并取模
long long factorial(int n) {
if ((n == 0) || (n == 1)) {
return 1;
}
return n * factorial(n -1) % MOD;
}
int main() {
int n;
cin >> n;
// 分别计算奇数和偶数的个数
int oddCount = (n + 1) / 2;
int evenCount = n / 2;
long long cnt = 0;
// 如果奇数和偶数的个数相差不超过 1,才可能存在满足条件的排列
if (abs(oddCount - evenCount) <= 1) {
// 当奇数和偶数个数相等时,排列可以从奇数或偶数开始
if (oddCount == evenCount) {
cnt = (2 * factorial(oddCount) * factorial(evenCount)) % MOD;
} else {
// 当奇数和偶数个数不相等时,排列只能从个数多的那种数开始
cnt = (factorial(oddCount) * factorial(evenCount)) % MOD;
}
}
cout << cnt << endl;
return 0;
} 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))
}