首页 > 试题广场 >

小红的双生排列

[编程题]小红的双生排列
  • 热度指数: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)
//如果你学过数学中排列组合 对于本体分析逻辑 可以很快找到规律 然后是如何处理数据并取模
//总结出来规律 你也可以写出以下代码

/*
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)