错排问题
题目链接:ybt高效进阶1-1-1 / luogu P1595
题目大意
求有多少个长度为 n 的排列,使 a i ≠ i a_i\neq i ai=i。
思路
当我们要摆第 n 个数的时候,我们考虑怎么摆。
首先,肯定是不能摆在自己的位置,别的都可以,所以后面弄的东西都要乘上
n
−
1
n-1
n−1。
接着,我们看,它要摆到前面,那它放的位置的数怎么办呢?
两种可能。
放到了最后的位置,也就是说它们两个互换了位置,那剩下的
n
−
2
n-2
n−2 个就重新再看错排。
没有放到最后,那就是说跟第
n
n
n 个数换的数就变成了第
n
n
n 个数(因为它也不能放在最后),那就是
n
−
1
n-1
n−1 个点的错排。
看到这个,我们想到用 dp。
那就是
f
i
=
(
n
−
1
)
∗
f
i
−
1
+
(
n
−
1
)
∗
f
i
−
2
f_i=(n-1)*f_{i-1}+(n-1)*f_{i-2}
fi=(n−1)∗fi−1+(n−1)∗fi−2。
至于初始化,就是
f
1
=
0
,
f
2
=
1
f_1=0,f_2=1
f1=0,f2=1。
因为没有取模,但是 n ≤ 20 n\leq 20 n≤20,所以用 long long 就可以了。
代码
#include<cstdio>
#define ll long long
using namespace std;
int n;
ll f[21];
int main() {
scanf("%d", &n);
f[1] = 0ll;
f[2] = 1ll;
for (int i = 3; i <= n; i++)
f[i] = (ll)(i - 1) * f[i - 2] + (ll)(i - 1) * f[i - 1];
printf("%lld", f[n]);
return 0;
}