错位排列
错位排列
一、错位排列:
1、定义:指没有任何元素出现在有序位置的排列,即对于长度为 \(n\) 的数组 \(a\),如果满足所有的 \(P_i \ne a_i\),则称 \(P\) 为数组 \(a\) 的错位排列。
2、利用容斥原理解决:
-
令集合 \(S_i\) 表示满足 \(P_i \ne a_i\) 的排列数目,\(U\) 为全集。
-
属性:\(P_i \ne a_i\)。
3、那么最终的公式为:\(D_n=n!-n!\sum_{k=1}^{n}\frac{(-1)^{k-1}}{k!}=n!\sum_{k=0}^{n}\frac{(-1)^k}{k!}\)。
4、错列排列的前几项为:\(0,1,2,9,44,265...\)。
5、递推式:\(D_n=(n-1)(D_{n-1}+D_{n-2})\),另递推式:\(D_n=nD_{n-1}+(-1)^n\)。
6、错列排序的简单表达式:\(D_n=\left \lfloor \frac{n!}{e} \right \rfloor = \left \lfloor \frac{n!}{e}+\frac{1}{2} \right \rfloor\)。(四舍五入)
7、另外可以推广到:
如果问你长度为 \(n\) 的数组 \(a\),如果保证 \(m\) 个位置稳定,即 \(P_i=a_i\),那么公式则为:\(D_{n}^{m}=C_{n}^{m}D_{n-m}\) 。
template<typename T>
struct C_per{
int N;
vector<T> D;
C_per(int N_, T p = 1e9 + 7) : D(N_ + 1) {
N = N_;
D[1] = 0;
D[2] = 1;
for (T i = 2; i <= N; i++) {
D[i] = (i - 1) * (D[i - 1] + D[i - 2]) % p;
}
}
inline T get(T n) {
return D[n];
}
};
另外推广的代码:
template<typename T>
struct C_fi{
inline T qp(T a, T b, T p = 1e9 + 7) {
i64 res = 1;
a %= p;
for (; b; b >>= 1LL, a = 1LL * a * a % p) {
if (b & 1) res = res * a % p;
}
return res;
}
inline T get_inv(T a, T p = 1e9 + 7) {
return qp(a, p - 2, p);
}
int N;
vector<T> fac, inv;
C_fi() {}
C_fi(int N_, T p = 1e9 + 7) : fac(N_ + 1), inv(N_ + 1) {
N = N_;
fac[0] = 1;
for (T i = 1; i <= N; i++) fac[i] = 1LL * fac[i - 1] * i % p;
inv[N] = get_inv(fac[N], p);
for (T i = N - 1; i >= 1; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % p;
}
inline T C(T n, T m, T p = 1e9 + 7) {
if (n < m) {
return (T)0;
}
return fac[n] * inv[n - m] % p * inv[m] % p;
}
};
template<typename T>
struct C_per{
int N;
C_fi st;
vector<T> D;
C_per(int N_, T p = 1e9 + 7) : D(N_ + 1) {
N = N_;
D[1] = 0;
D[2] = 1;
for (T i = 2; i <= N; i++) {
D[i] = (i - 1) * (D[i - 1] + D[i - 2]) % p;
}
st = C_fi<T>(N, p);
}
inline T get(T n, T m, T p = 1e9 + 7) {
if (n < m) {
return (T)0;
}
return st.C(n, m, p) * D[n - m] % p;
}
};

浙公网安备 33010602011771号