惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Palo Alto Networks Blog
大猫的无限游戏
大猫的无限游戏
Martin Fowler
Martin Fowler
GbyAI
GbyAI
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
量子位
T
The Blog of Author Tim Ferriss
Y
Y Combinator Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
CERT Recently Published Vulnerability Notes
Recent Announcements
Recent Announcements
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
P
Privacy International News Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
博客园 - 叶小钗
L
Lohrmann on Cybersecurity
G
GRAHAM CLULEY
T
The Exploit Database - CXSecurity.com
Hugging Face - Blog
Hugging Face - Blog
P
Proofpoint News Feed
NISL@THU
NISL@THU
博客园 - Franky
C
Cybersecurity and Infrastructure Security Agency CISA
The Register - Security
The Register - Security
M
MIT News - Artificial intelligence
Know Your Adversary
Know Your Adversary
A
Arctic Wolf
F
Full Disclosure
T
Threat Research - Cisco Blogs
P
Privacy & Cybersecurity Law Blog
The Hacker News
The Hacker News
博客园 - 【当耐特】
D
Docker
T
Tailwind CSS Blog
S
SegmentFault 最新的问题
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Jina AI
Jina AI
Help Net Security
Help Net Security
V
Visual Studio Blog
小众软件
小众软件
B
Blog
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
N
Netflix TechBlog - Medium
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
Cisco Blogs
Security Archives - TechRepublic
Security Archives - TechRepublic

博客园 - RonChen

同余分析 差分约束 Treap 点分治 莫队算法 分块 扫描线 Sprague-Grundy (SG) 函数及其应用 容斥原理 卢卡斯定理 线性基 高斯消元 勒让德公式 次短路 分层图最短路 01 图最短路 洪水填充 双向搜索 迭代加深搜索 剪枝 最小表示法 表达式计算 KMP 算法 队列 高精度运算
错排问题
RonChen · 2026-04-23 · via 博客园 - RonChen

求有多少 \(1 \sim n\) 的排列 \(p\) 满足对于任意 $i = 1, \dots, n $,有 \(p_i \ne i\)

方法 1(递推):\(D_i = (D_{i-1} + D_{i-2}) \times (i-1)\),其中 \(D_0 = 1, \ D_1 = 0\)

第一种情况,前 \(i-1\) 位形成错排,第 \(i\) 位跟前 \(i-1\) 位里的任意一位交换。

第二种情况,有 \(i-2\) 位形成错排,第 \(i\) 位跟前 \(i-1\) 位里唯一 \(p_i = i\) 的交换。

方法 2(容斥):\(D_n = \sum \limits_{k=0}^n (-1)^k \times C_n^k \times (n-k)!\)

可以继续简化为 \(D_n = \sum \limits_{k=0}^n (-1)^k \times \dfrac{n!}{k!(n-k)!} \times (n-k)! = n! \times \sum \limits_{k=0}^n \dfrac{(-1)^k}{k!}\)

其中 \(n!\) 可以从 \((n-1)!\) 递推,后边的求和项也是会比算 \(D_{n-1}\) 时多一项,所以这个 \(D_n\) 的表达式也可以递推。

例题:P4071 [SDOI2016] 排列计数

\(n\) 个位置中选出 \(m\) 个位置固定 \(a_i = i\),其它位置进行错排。

因此答案为 \(C_n^m \times D_{n-m}\)\(D\) 表示错排数)。

组合数使用预处理阶乘和阶乘逆元的方法求。

参考代码
#include <cstdio>
const int N = 1000005;
const int MOD = 1000000007;
int d[N], f[N], g[N];
int qpow(int x, int y) {
    int res = 1;
    while (y > 0) {
        if (y & 1) res = 1ll * res * x % MOD;
        x = 1ll * x * x % MOD;
        y >>= 1;
    }
    return res;
}
void init(int n) {
    f[0] = 1; g[0] = 1;
    for (int i = 1; i <= n; i++) f[i] = 1ll * f[i - 1] * i % MOD;
    g[n] = qpow(f[n], MOD - 2);
    for (int i = n - 1; i > 0; i--) g[i] = 1ll * g[i + 1] * (i + 1) % MOD;
    d[0] = 1; d[1] = 0; 
    for (int i = 2; i <= n; i++) d[i] = 1ll * (i - 1) * (d[i - 1] + d[i - 2]) % MOD;
}
int C(int n, int m) {
    return 1ll * f[n] * g[m] % MOD * g[n - m] % MOD;
}
int main()
{
    int t; scanf("%d", &t);
    init(1000000);
    for (int i = 1; i <= t; i++) {
        int n, m; scanf("%d%d", &n, &m);
        int ans = m > n ? 0 : 1ll * C(n, m) * d[n - m] % MOD;
        printf("%d\n", ans);
    }
    return 0;
}