专栏文章

题解:P12369 [蓝桥杯 2022 省 Python B] 全排列的价值

P12369题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipfmm3z
此快照首次捕获于
2025/12/03 11:13
3 个月前
此快照最后确认于
2025/12/03 11:13
3 个月前
查看原文

P12369 [蓝桥杯 2022 省 Python B] 全排列的价值 题解

思路

分享一种不用逆元的做法。
考虑线性递推。设答案为 f(n)f(n),那么对于前面已知的 f(n1)f(n-1),设它的一种全排列方式为 a1,a2,a3,,an1a_1,a_2,a_3,\cdots,a_{n-1}
如图,将 nn 的增加视为向这个排列内插入一个 nn,算上该序列的头尾,共有 nn 个位置可以插,插在第 kk 个位置上的贡献即为该位置前方元素的数量,即 k1k-1(因为这时 nn 一定是最大的,前面的所有元素都比它小,后面的所有元素都没它大,所以只对前面有影响)。因此该排列下插入带来的贡献为:
k=1nk1=n(n1)2\sum^n_{k=1}k-1=\dfrac{n(n-1)}{2}
(挺显然的说是…)
每次不同的插入方法都视为一种答案,nn 种方法,就需要将原答案数乘 nn。在 n1n-1 下的 (n1)!(n-1)! 个排列都得计算一遍,合起来就是总答案的 nn 倍与插入带来的总贡献 n(n1)2(n1)!\dfrac{n(n-1)}{2}(n-1)! 之和。初始的状态为 n=2n=2,答案显然为 11。于是我们即可得到递推式:
1 & n=2\\ nf(n-1)+\dfrac{n(n-1)}{2}(n-1)! & n>2 \end{cases}$$ 时间复杂度 $O(n)$。阶乘采用预处理。 ### C++ ```cpp #include<bits/stdc++.h> #define ll long long using namespace std; const ll N=1e6+5,mod=998244353; ll n,ans[N],jc[N]={1,1}; int main() { cin>>n; ans[2]=1; for(int i=1; i<=N; i++) jc[i]=jc[i-1]*i%mod;//阶乘预处理 for(int i=3; i<=n; i++) ans[i]=(i*1ll*ans[i-1]%mod+i*1ll*(i-1)/2ll%mod*1ll*jc[i-1]%mod)%mod; //记住在常数后面加 ll 防止转 int 炸掉 //由于 i*(i-1) 一定为偶数,所以可以直接 /2 而不用考虑逆元 cout<<ans[n]%mod; return 0; } ``` ### Python ```python mod = 998244353 N = 1000005 n = int(input()) ans = [0] * N ans[2] = 1 jc = [1] * N for i in range(1, N): jc[i] = (jc[i-1] * i) % mod for i in range(3, n + 1): t1 = (i * ans[i-1]) % mod t2 = ((i * (i - 1) // 2) % mod) * jc[i-1] % mod ans[i] = (t1 + t2) % mod print(ans[n] % mod) ``` upd on 2025/5/5 18:30:添加了 Python 代码。 upd on 2025/6/7 22:05:修改了凌乱冗余的语言描述,增强可读性。

评论

0 条评论,欢迎与作者交流。

正在加载评论...