[笔记]自己想的一个题,解题思路以及代码
自己在学校想到的,很大概率是已经存在的原题,不过这道题很有趣,所以记录一下
题意简述
输入一个\(N\),询问\(\{1,2,…,N\}\)的所有全排列中满足下列条件的排列\(P\)的个数取模\(998244353\)的值:
- 定义\(A\)数组,初始全为空。对于\(1\leq i\leq N\),设\(A_{P_i}\)为\(i\)。如果\(A=P\),则满足条件。
说明:\(1\leq N \leq 10^7\)
样例及解释
Input: 3
Output: 4
\(\{1,2,3\}\)的全排列有\(\{1,2,3\},\{1,3,2\},\{2,1,3\},\{2,3,1\},\{3,1,2\},\{3,2,1\}\)。
依照规则填写的\(A\)分别是\(\{1,2,3\},\{1,3,2\},\{2,1,3\},\textcolor{red}{\{3,1,2\}},\textcolor{red}{\{2,3,1\}},\{3,2,1\}\)。
红色的是不匹配的,于是答案为\(4\)。
解题思路
根据题意,满足条件必须要求\(A_i=P_i,A_{P_i}=i\)
\(A_i=P_i\)即\(A_{P_i}=P_{P_i}\)
又因为\(A_{P_i}=i\),所以\(P_{P_i}=i\)
满足\(P_{P_i}=i\)的\(P\)即为符合条件,接下来我们用dp解决。
设\(dp_i\)为\(N=i\)时的答案,初始\(dp_1=1,dp_2=2\)。
递推式:\(dp_i=dp_{i-1}+(i-1)*dp_{i-2}\)
怎么推导的呢?我画个图,通过\(N=4\)的情况解释:
下面附上代码实现↓
Code
可以用滚动数组优化空间。(懒)
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
int n,dp[10000010];
signed main(){
cin>>n;
dp[1]=1,dp[2]=2;
for(int i=3;i<=n;i++){
dp[i]=(dp[i-1]+((i-1)*dp[i-2])%mod)%mod;
}
cout<<dp[n];
return 0;
}
\[[THE\ \ END]
\]
注:若发现错误或改进建议,请在评论区指出,感谢万分!