第十三届蓝桥杯省赛Java A 组 F 题、Python A 组 G 题、Python B 组 G题——全排列的价值 (AC)

1.全排列的价值

1.题目描述

对于一个排列 A A A= ( a 1 , a 2 , ⋯   , a n ) \left(a_{1}, a_{2}, \cdots, a_{n}\right) (a1,a2,,an), 定义价值 c i c_{i} ci a 1 a_{1} a1 a i − 1 a_{i-1} ai1中小于 a i a_{i} ai的数 的个数, 即 c i = ∣ { a j ∣ j < i , a j < a i } ∣   c_{i}=\mid\left\{a_{j} \mid j<i, a_{j}<a_{i}\right\} |_{\text { }} ci={ajj<i,aj<ai}  定义 A A A 的价值为 ∑ i = 1 n c i \sum_{i=1}^{n} c_{i} i=1nci。给定 n n n, 求 1 1 1 n n n 的全排列中所有排列的价值之和。

2.输入格式

输入一行包含一个整数 n n n

3.输出格式

输出一行包含一个整数表示答案, 由于所有排列的价值之和可能很大, 请 输出这个数除以 998244353 的余数。

4.样例输入1

3

5.样例输出2

2022

6.样例输出1

9

7.样例输出2

593300958

8.样例解释

1 至 3 构成的所有排列的价值如下:

( 1 , 2 , 3 ) : 0 + 1 + 2 = 3 ( 1 , 3 , 2 ) : 0 + 1 + 1 = 2 ( 2 , 1 , 3 ) : 0 + 0 + 2 = 2 ( 2 , 3 , 1 ) : 0 + 1 + 0 = 1 ( 3 , 1 , 2 ) : 0 + 0 + 1 = 1 ( 3 , 2 , 1 ) : 0 + 0 + 0 = 0 \begin{aligned} &(1,2,3): 0+1+2=3 \\ &(1,3,2): 0+1+1=2 \\ &(2,1,3): 0+0+2=2 \\ &(2,3,1): 0+1+0=1 \\ &(3,1,2): 0+0+1=1 \\ &(3,2,1): 0+0+0=0 \end{aligned} (1,2,3):0+1+2=3(1,3,2):0+1+1=2(2,1,3):0+0+2=2(2,3,1):0+1+0=1(3,1,2):0+0+1=1(3,2,1):0+0+0=0

故总和为 3 + 2 + 2 + 1 + 1 = 9 3+2+2+1+1=9 3+2+2+1+1=9

9.原题链接

全排列的价值

2.解题思路

  做过逆序对问题的话,明显可以看出对于任意一个排序,其价值等于逆序对的数量。考虑使用dp来进行递推,我们定义 f ( n ) f(n) f(n) 1 1 1 n n n 的全排列中所有排列的价值之和,明显可以得到 f ( 1 ) = 0 , f ( 2 ) = 1 。 f(1)=0,f(2)=1。 f(1)=0f(2)=1

  核心问题在于:如何从 f ( n − 1 ) f(n-1) f(n1) 递推得到 f ( n ) f(n) f(n) 的值?我们以 n n n4 时来进行举例,仔细观察 3 3 3 的全排列:
( 1 , 2 , 3 ) ( 1 , 3 , 2 ) ( 2 , 1 , 3 ) ( 2 , 3 , 1 ) ( 3 , 1 , 2 ) ( 3 , 2 , 1 ) \begin{aligned} &(1,2,3) \\ &(1,3,2)\\ &(2,1,3) \\ &(2,3,1) \\ &(3,1,2) \\ &(3,2,1)\end{aligned} (1,2,3)(1,3,2)(2,1,3)(2,3,1)(3,1,2)(3,2,1)
此时我们在这些排列的基础上插入4,无论在哪个排列中插入4,都有4个插入的位置, 比如插入第一个排列 ( 1 , 2 , 3 ) (1,2,3) (1,2,3)时可以得到下面这四种情况:
( 4 , 1 , 2 , 3 ) ( 1 , 4 , 2 , 3 ) ( 1 , 2 , 4 , 3 ) ( 1 , 2 , 3 , 4 ) \begin{aligned} &(4,1,2,3) \\ &(1,4,2,3)\\ &(1,2,4,3) \\ &(1,2,3,4) \end{aligned} (4,1,2,3)(1,4,2,3)(1,2,4,3)(1,2,3,4)

我们每个排列只看元素4带来的贡献分别为 0 + 1 + 2 + 3 = 6 0+1+2+3=6 0+1+2+3=6,对于3的任何一个排列我们插入4带来的价值都一样,这是因为我们在 n − 1 n-1 n1 的全排列插入 n n n时,排列中的元素都严格小于 n n n,所以我们当 n n n 插入的位置之前有几个元素,则带来的价值就是几 。根据该推导可知:当在 n − 1 n-1 n1的任何一个排列中插入 n n n 时, n n n 带来的贡献则为 ∑ i = 1 n − 1 i \sum_{i=1}^{n-1} i i=1n1i,也就是从 1 1 1 累加到 n − 1 n-1 n1,我们可以使用高斯求和计算。当然这只是一个排列带来的价值,对于 n n n 而言,它的全排列的数量为 n ! n ! n!,我们设 g ( n ) g(n) g(n) n n n 的全排列的数量,也就是 n n n 的阶乘。我们上述只考虑了 n n n 给我们带来的价值,我们当然还得考虑其他数,对于排列 ( 1 , 2 , 3 ) (1,2,3) (1,2,3),在插入4后有四种情况,它自己也变成了4份,价值也相应变成了4倍,3的任何一个排列的价值都是如此,由此我们可以得知,当从 f ( n − 1 ) f(n-1) f(n1) 递推到 f ( n ) f(n) f(n) 时, f ( n − 1 ) f(n-1) f(n1) 会变成 n n n 倍,根据上述的推导我们可以得到递推转移公式:
f ( n ) = f ( n − 1 ) × n + i × ( i − 1 ) 2 × g ( n − 1 ) f(n)=f(n-1)\times n+ \frac {i \times(i-1)} {2} \times g(n-1) f(n)=f(n1)×n+2i×(i1)×g(n1)

当然答案很大,在推导过程中需要进行取模。

3. Ac_code

import java.io.*;

public class Main {
    static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    static long[] f=new long[1000010];
    static long[] g=new long[1000010];
    static int MOD=998244353;
    public static void main(String[] args) throws IOException {
        int n=Integer.parseInt(br.readLine());
        f[1]=0;
        init(n);
        for (int i = 2; i <=n; i++) {
            f[i]=(f[i-1]*i%MOD+(long)i*(i-1)/2%MOD*g[i-1]%MOD)%MOD;
        }
        out.println(f[n]);
        out.flush();
    }
    static void init(int n){
        long h=1;
        for (int i = 1; i <=n; i++) {
            h*=i;
            h%=MOD;
            g[i]=h;
        }
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

执 梗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值