Luogu P1595 信封问题
\(\large{题目链接}\)
\(\\\)
题意:
某人写了\(n\)封信和\(n\)个信封,如果所有的信都装错了信封。求所有信都装错信封共有多少种不同情况。
思路:
1.依据递推公式:\(D_n = (n-1)\times (D_{n-1} +D_{n-2})\)
2.学习二项式反演发现这题也可以用这个做。
首先二项式反演的公式是:\(f_{n}=\sum \limits^{n}_{i=0}\left( -1\right) ^{i}\begin{pmatrix}
n \\
i
\end{pmatrix}g_{i} \Leftrightarrow g_{n}=\sum \limits^{n}_{i=0}\left( -1\right) ^{i}\begin{pmatrix}
n \\
i
\end{pmatrix}f_{i}\)
更常用的式子是\(f_{n}=\sum \limits^{n}_{i=0}\begin{pmatrix}
n \\
i
\end{pmatrix}g_{i}\Leftrightarrow g_{n}=\sum \limits^{n}_{i=0}\left( -1\right) ^{n-i}\begin{pmatrix}
n \\
i
\end{pmatrix}f_{i}\)
回归这个题,我们知道\(n\)个信的排列的方案数是\(n!\)。
设\(f_i\)表示有\(i\)恰好有\(i\)个位置改变的排列个数,那么\(n\)个的排列总数就是\(i = 0,1,...,n-1,n\)的和,即\(n! = \sum \limits^{n}_{i=0}\begin{pmatrix}
n \\
i
\end{pmatrix}f_{i}\),观察这个式子,与刚刚的反演式子很相似,这里的\(n!\)就是\(g_n\)。
那么利用二项式反演公式可以得到:
由于没有逆元,所以把\(n!\)提进去。
代码:
#include <bits/stdc++.h>
typedef long long ll;
int main() {
ll fac[23];
fac[0] = fac[1] = 1;
for (int i = 2; i <= 20; ++i) fac[i] = fac[i - 1] * i;
int n;
std::cin >> n;
ll ans = 0;
for (int i = 0; i <= n; ++i) ans += (i & 1) ? -(fac[n] / fac[i]) : fac[n] / fac[i];
std::cout << ans;
return 0;
}