首页 > 试题广场 >

小红的双生排列

[编程题]小红的双生排列
  • 热度指数: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\} 且为双生排列。
主要考察防止数值溢出的取模知识,本题为排列知识,例如当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);
            }

        }
    }
}

发表于 2025-07-19 15:07:04 回复(0)
#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;
}

发表于 2025-05-13 15:11:59 回复(0)
n = int(input())

def cal_all(n):
    res = 1
    for n in range(1,int(n)+1):
        res = res*n
    return res

if n%2==1:
    a = n/2+1
    b = n/2
    print(cal_all(a)*cal_all(b))
else:
    a= n/2
    b = n/2
    print(cal_all(a)*cal_all(b))

发表于 2025-04-20 11:59:16 回复(0)
#include <iostream>
using namespace std;

const long long mod=1e9+7;

long getMotify(long p)
{
if(p==1)return 1;
return (p%mod)*(getMotify(p-1)%mod)%mod;
}

int main() {
int n;cin>>n;
int Gn,On;
if(n&1)
{
Gn=(n+1)/2;On=Gn-1;
cout<<(getMotify(Gn)*getMotify(On))%mod<<endl;
}else {
Gn=On=n/2;
cout<<(2*getMotify(Gn)*getMotify(On))%mod<<endl;
}
}
// 64 位输出请用 printf("%lld")
发表于 2025-04-16 16:24:52 回复(0)
#排列组合问题,奇偶分开排列
#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)

发表于 2025-04-14 22:05:48 回复(0)
如果奇数和偶数的个数相差不超过 1,才可能存在满足条件的排列
1. 分别计算奇数和偶数的个数
2.当奇数和偶数个数相等时,排列可以从奇数或偶数开始
3.当奇数和偶数个数不相等时,排列只能从个数多的那种数开始

#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;
}    


发表于 2025-04-09 14:20:57 回复(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))
}

发表于 2025-04-07 11:57:51 回复(0)
//如果你学过数学中排列组合 对于本体分析逻辑 可以很快找到规律 然后是如何处理数据并取模
//总结出来规律 你也可以写出以下代码

/*
import java.math.BigInteger;
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = in.nextInt();
        BigInteger moshu = new BigInteger("1000000007");
        BigInteger result = new BigInteger("1");
        if(n==1){
            System.out.println(0);
        }else if(n==2){
            System.out.println(2);
        } else if (n%2!=0) {//为奇数
            for(int i = 2;i<=(n+1)/2;i++){
                result = result.multiply(BigInteger.valueOf(i));
            }
            for(int i = 2;i<=(n-1)/2;i++){
                result = result.multiply(BigInteger.valueOf(i));
            }
            System.out.println(result.mod(moshu));
        }else{//偶数情况
            result = result.multiply(BigInteger.valueOf(2));
            for(int i = 2;i<=n/2;i++){
                result = result.multiply(BigInteger.valueOf(i));
            }
            for(int i = 2;i<=n/2;i++){
                result = result.multiply(BigInteger.valueOf(i));
            }
            System.out.println(result.mod(moshu));
        }
    }
}
*/
/*
//问题在于会超时 卡在用例14 输入90081 答案是294388414    修改后如下

import java.math.BigInteger;
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = in.nextInt();
        BigInteger moshu = new BigInteger("1000000007");
        BigInteger result1 = new BigInteger("1");
        if (n == 1) {
            System.out.println(0);
        } else if (n == 2) {
            System.out.println(2);
        } else if (n % 2 != 0) { //为奇数
            BigInteger result = new BigInteger("1");
            for (int i = 2; i <= (n - 1) / 2; i++) {
                result1 = result1.multiply(BigInteger.valueOf(i));
            }
            result = result1.pow(2).multiply(BigInteger.valueOf((n + 1) / 2));
            System.out.println(result.mod(moshu));
        } else { //偶数情况
            BigInteger result = new BigInteger("2");
            for (int i = 2; i <= n / 2; i++) {
                result1 = result1.multiply(BigInteger.valueOf(i));
            }
            result = result.multiply(result1.pow(2));
            System.out.println(result.mod(moshu));
        }
    }
}
*/
//这里运行处理时间是1131ms 我写的
//经过分析后发现 可以用平方呀 这样大大减少了时间 隔壁兄弟说超时的 提醒我了 我一开始也遇到相同情况 所以python是可以过搭 虽然我用的是java不过python也可以平方吧

//后续 离谱了 问了文老师如何改进 缩短时间 它告诉我可以预处理阶乘 大大缩短时间 ps:因为BigInteger运算时间很长很慢

//以下是文老师 运行处理时间是36ms 离谱了!!!
import java.math.BigInteger;
import java.util.Scanner;

// 示例:使用预计算阶乘数组



// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {

static final int MOD = 1000000007;
static int[] fact;
static final int MAX_N = 100000;


    public static void main(String[] args) {
    // 预计算阶乘(仅需一次)
    Scanner in = new Scanner(System.in);
        int n = in.nextInt();
    fact = new int[MAX_N+1];
    fact[0] = 1;
    for(int i=1; i<=MAX_N; i++){
        fact[i] = (int)((long)fact[i-1]*i % MOD);
    }

    // 查询时直接计算
    if(n%2 !=0){
        int k = (n-1)/2;
        long res = (long)fact[k] * fact[k] % MOD;
        res = res * (k+1) % MOD;
        System.out.println(res);
    }else{
        int k = n/2;
        long res = (long)fact[k] * fact[k] % MOD;
        res = res * 2 % MOD;
        System.out.println(res);
    }
    }
}
发表于 2025-04-06 19:02:55 回复(0)
#感觉python3就运行不过去,19个例子卡住了
import sys

n = int(input())
def jiecheng(k):
    sum = 1
    for i in range(1,k+1):
        sum *= i
    return sum

if n%2 == 0:
    k = int(n/2)
    num = (2*jiecheng(k)*jiecheng(k))%(10**(9)+7)
else:
    k = int(n/2)
    num = (jiecheng(k)*jiecheng(k+1))%(10**(9)+7)
print(num)
发表于 2025-03-30 22:33:48 回复(0)