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

推荐订阅源

N
News and Events Feed by Topic
WordPress大学
WordPress大学
Vercel News
Vercel News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
小众软件
小众软件
L
LangChain Blog
雷峰网
雷峰网
D
DataBreaches.Net
博客园 - 三生石上(FineUI控件)
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
NISL@THU
NISL@THU
Scott Helme
Scott Helme
量子位
S
Security Affairs
T
Threat Research - Cisco Blogs
博客园_首页
云风的 BLOG
云风的 BLOG
D
Docker
AWS News Blog
AWS News Blog
腾讯CDC
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
U
Unit 42
Recent Announcements
Recent Announcements
Apple Machine Learning Research
Apple Machine Learning Research
G
Google Developers Blog
T
The Exploit Database - CXSecurity.com
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 热门话题
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The Last Watchdog
The Last Watchdog
C
Cybersecurity and Infrastructure Security Agency CISA
IT之家
IT之家
W
WeLiveSecurity
P
Privacy & Cybersecurity Law Blog
F
Full Disclosure
L
Lohrmann on Cybersecurity
The Hacker News
The Hacker News
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Y
Y Combinator Blog
S
Security @ Cisco Blogs
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Check Point Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
N
News and Events Feed by Topic
PCI Perspectives
PCI Perspectives
I
InfoQ

博客园 - RonChen

区间合并 距离和的最小值 归并排序与逆序对 快速排序与快速选择 同余分析 差分约束 Treap 点分治 莫队算法 分块 扫描线 错排问题 Sprague-Grundy (SG) 函数及其应用 容斥原理 卢卡斯定理 线性基 高斯消元 勒让德公式 次短路 分层图最短路 01 图最短路 洪水填充 双向搜索 迭代加深搜索 剪枝 最小表示法 表达式计算 KMP 算法 队列 高精度运算
抽屉原理
RonChen · 2026-07-24 · via 博客园 - RonChen

抽屉原理(又称鸽巢原理)是组合数学中最基础但又极其强大的工具之一,它的核心思想极其直观:如果物品的数量多于容器的数量,那么至少有一个容器里盛放了不止一个物品。虽然原理本身非常简单,但通过巧妙地“构造抽屉”和“确定物品”,它可以用来证明很多看似难以下手的存在性问题。

简单抽屉原理:若将 \(n+1\) 个物体放入 \(n\) 个抽屉,则至少有一个抽屉中包含 \(2\) 个或 \(2\) 个以上的物体。

证明

反证法

假设每个抽屉包含的物体数量都少于 \(2\) 个(即最多包含 \(1\) 个),那么 \(n\) 个抽屉所能容纳的物体总数最多为 \(n \times 1 = n\) 个,这与总共有 \(n+1\) 个物体的已知条件相矛盾。因此,假设不成立,原命题成立。

例如:\(13\) 个人中,至少有 \(2\) 个人的出生月份相同(\(13\) 个物品放入 \(12\) 个月份抽屉);从一副扑克牌中任意抽取 \(5\) 张普通牌(不含大小王),因为扑克牌只有 \(4\) 种花色(黑桃、红心、梅花、方块),所以至少有 \(2\) 张牌的花色相同(\(5\) 个物品放入 \(4\) 个花色抽屉)。

在实际应用中,物品的数量往往多于抽屉的数量,此时需要更一般的结论。

推广抽屉原理:若将 \(N\) 个物体放入 \(k\) 个抽屉中,则至少有一个抽屉中包含不少于 \(\lceil \frac{N}{k} \rceil\) 个物体。

推论(加权/平均值形式):若 \(a_1 + a_2 + \cdots + a_k = N\),则存在至少一个 \(i \in \{ 1, 2, 3, \dots, k \}\),使得 \(a_i \ge \lceil \frac{N}{k} \rceil\)

反向表达(极值推论):要确保至少有一个抽屉里有 \(m\) 个物体,物体的总数 \(N\) 至少需要达到 \(N = k(m-1)+1\)

练习:在 \(1,2,3,\dots,10\)\(10\) 个自然数中,任意取出 \(6\) 个数,证明“其中必有两个数的和等于 \(11\)”。

证明

将这 \(10\) 个数配对成 \(5\) 个集合(抽屉)\(\{ 1,10 \}, \{ 2,9 \}, \{ 3,8 \}, \{ 4,7 \}, \{ 5,6 \}\),共 \(5\) 个抽屉。从 \(10\) 个数中取出 \(6\) 个数(\(6\) 个物体),根据抽屉原理,至少有两个数来自于同一集合。而每个集合中两数之和均为 \(11\),故必有两个数的和等于 \(11\)

练习:在一个 \(3 \times 7\) 的网格图中,每个小方格涂上红色或蓝色,证明“图中必然存在一个矩形,它的四个角上的小方格颜色完全相同”。

证明

考虑每一列的 \(3\) 个格子的颜色,因为只有 \(2\) 种颜色,根据抽屉原理,每列的 \(3\) 个格子中至少有 \(2\) 个格子颜色相同(同红或同蓝)。

每一列中“相同颜色的两个位置”共有 \(C_3^2 = 3\) 种位置组合 \((1,2), (2,3), (1,3)\),且颜色有 \(2\) 种(红/蓝),因此位置组合与颜色的形态共有 \(3 \times 2 = 6\) 种(即 \(6\) 个抽屉)。

网格一共有 \(7\) 列(\(7\) 个物体),根据抽屉原理,在这 \(7\) 列中,至少有 \(2\) 列具有完全相同的“同色位置与颜色”形态,这两列中对应的 \(4\) 个角上的方格就构成了一个四角同色的矩形。


在数论中,余数是天然的“抽屉”。模 \(m\) 的余数只有 \(0, 1, 2, \dots, m-1\)\(m\) 种可能。

例题:证明“任意给定 \(n+1\) 个整数,其中必有两个数的差是 \(n\) 的倍数”。

证明

给定的 \(n+1\) 个整数 \(a_1, a_2, \dots, a_{n+1}\)\(n+1\) 个物体,按照除以 \(n\) 的余数分类。任何整数除以 \(n\) 的余数只能是 \(0,1,2, \dots, n-1\),共 \(n\) 种可能的余数(共 \(n\) 个抽屉)。把 \(n+1\) 个整数按其余数放入 \(n\) 个抽屉中,根据抽屉原理,必有两个整数 \(a_i\)\(a_j \ (i \ne j)\) 落在同一个抽屉中,即它们除以 \(n\) 的余数相同。余数相同,则它们的差 \(a_i-a_j\) 必能被 \(n\) 整除。

练习:证明“在任意给定的 \(n\) 个整数 \(a_1, a_2, \dots, a_n\) 中,必能找到若干个连续的数,它们的和能够被 \(n\) 整除”。

证明

考虑 \(n\) 个前缀和 \(S_1, S_2, \dots, S_n\),若其中某个 \(S_k \equiv 0 \pmod{n}\),则前 \(k\) 个数之和就能被 \(n\) 整除,命题得证。

若所有 \(S_k\) 都不能被 \(n\) 整除,则它们模 \(n\) 的余数只能在 \(1,2, \dots, n-1\) 中取值(共 \(n-1\) 种余数,即 \(n-1\) 个抽屉)。

\(n\) 个前缀和放入这 \(n-1\) 个抽屉中,由抽屉原理,必有两个前缀和 \(S_i\)\(S_j \ (i \lt j)\)\(n\) 同余,即 \(S_j \equiv S_i \pmod{n}\),此时连续段之和 \(\sum \limits_{k=i+1}^j a_k = S_j - S_i\) 必能被 \(n\) 整除。


几何问题通常利用面积划分距离分割来构造抽屉。

例题:证明“在边长为 \(1\) 的正方形内任意放入 \(5\) 个点,必有两个点之间的距离不超过 \(\frac{\sqrt{2}}{2}\)”。

证明

将边长为 \(1\) 的正方形连接各边中点,等分成 \(4\) 个边长为 \(\frac{1}{2}\) 的小正方形。将 \(5\) 个点放入 \(4\) 个小正方形中,由抽屉原理,至少有 \(2\) 个点落在同一个边长为 \(\frac{1}{2}\) 的小正方形内(或边界上)。边长为 \(\frac{1}{2}\) 的正方形内,任意两点间的最大距离即为其对角线长 \(d_{\max} = \sqrt{ \left( \frac{1}{2} \right) ^2 + \left( \frac{1}{2} \right) ^2 } = \frac{\sqrt{2}}{2}\)。因此,这两个点之间的距离必然不超过 \(\frac{\sqrt{2}}{2}\)


图论中的节点度数、边着色等问题,经常可以通过抽屉原理寻找对称性或局部结构。

例题:假设在一个由 \(6\) 个人组成的群体中,任意两个人之间的关系恰为两种之一(两两相互认识,或者两两相互不认识,即“认识”关系满足对称性),证明“该群体中必然存在 \(3\) 个人,他们两两相互认识;或者存在 \(3\) 个人,他们两两相互不认识”。

证明

\(6\) 个人抽象为无向图 \(G\)\(6\) 个顶点 \(V = \{ v_1, v_2, \dots, v_6 \}\),任意两个顶点之间都有连线(构成完全图 \(K_6\)):若两人相互认识,则连线涂成红色;若两人相互不认识,则连线涂成蓝色

问题严格转化为:证明在用 \(2\) 种颜色对 \(K_6\)\(15\) 条边进行任意着色后,图中必然存在一个同色三角形(全红三角形或全蓝三角形)

任意挑选一个顶点 \(A\),在完全图 \(K_6\) 中,除去 \(A\) 之外还有 \(5\) 个顶点,因此从 \(A\) 出发共有 \(5\) 条边。这 \(5\) 条边只能涂上红色或蓝色(\(2\) 个颜色抽屉)。将 \(5\) 条边放入 \(2\) 种颜色抽屉中,根据推广抽屉原理,从 \(A\) 出发的 \(5\) 条边中,至少有 \(3\) 条边的颜色相同

不妨设这 \(3\) 条同色边分别连接到顶点 \(B,C,D\),且颜色均为红色。考察 \(B,C,D\) 这三个顶点之间的 \(3\) 条连线 \((B,C),(C,D),(D,B)\)

  • 情况 A:若这 \(3\) 条边中存在至少一条红边(例如边 \((B,C)\) 为红色),则顶点 \(A,B,C\) 构成的三角形三条边 \((A,B),(A,C),(B,C)\) 均为红色,即存在 \(3\) 个人两两相互认识。
  • 情况 B:若这 \(3\) 条边中没有任何红边,这意味着 \((B,C),(C,D),(D,B)\) 全部为蓝边,则顶点 \(B,C,D\) 本身构成一个全蓝三角形,即存在 \(3\) 个人两两相互不认识。

综上所述,无论边如何着色,均能保证存在一个同色三角形,即群体中必存在 \(3\) 个人两两相互认识或两两相互不认识。

例题:P4090 [USACO17DEC] Greedy Gift Takers P

\(N \ (1 \le N \le 10^5)\) 头奶牛排成一队(编号从 \(1\)\(N\)),初始时奶牛 \(1\) 在队首,奶牛 \(N\) 在队尾。Farmer John 按以下规则发礼物:

  1. 位于队首的奶牛拿到一份礼物。
  2. 拿到礼物的奶牛 \(i\) 会选择插队,使得其身后恰好留有 \(c_i \ (0 \le c_i \le N-1)\) 头奶牛(即插入到队首数起的第 \(N-c_i\) 个位置)。
  3. 重复上述过程。

在送出无限份礼物的过程中,请求出永远无法拿到礼物的奶牛数量。

若编号为 \(k\) 的奶牛能够拿到礼物,说明在前 \(k-1\) 头奶牛不断领礼物插队的过程中,队首指针能够顺利推进到第 \(k\) 头奶牛。由于前面的奶牛领完礼物后只会插入到队列的某个位置,不会凭空消失;如果第 \(k\) 头奶牛能够到达队首,那么所有编号小于 \(k\) 的奶牛必然也都在它之前到达过队首并拿到了礼物。因此,能够拿到礼物的奶牛编号必然构成一个连续的前缀 \([1, k]\),具有单调性。可以通过二分答案,在 \(O(\log N)\) 次检查内确定最大能拿到礼物的奶牛编号 \(k\),最终永远无法拿到礼物的奶牛数量即为 \(n-k\)

需要判定“在前 \(k-1\) 头奶牛领礼物的过程中,第 \(k\) 头奶牛能否成功到达队首?”。

奶牛 \(i\) 领到礼物后,身后留有 \(c_i\) 头奶牛,这意味着它插队后的位置为从队首数起第 \(N-c_i\) 个位置\(c_i\) 的值越大,说明插队后身后留的人越多,则越靠近队首(位置编号 \(N-c_i\) 越小)。如果关注队列最前面的 \(N-x\) 个位置(其中 \(x \in [0,N-1]\)),那么只有满足 \(N-c_i \le N-x\)(即 \(c_i \ge x\))的奶牛,插队后才会落在队首的前 \(N-x\) 个位置之内

在前 \(k-1\) 头奶牛中,设恰有 \(s\) 头奶牛满足 \(c_i \le x\)(这些奶牛插队位置较靠后,落在第 \(N-x\) 个位置之后),那么剩下的 \(k-1-s\) 头奶牛均满足 \(c_i \ge x\)(这些奶牛插队位置均落在队首前 \(N-x\) 个位置之内)。此时,包含第 \(k\) 头奶牛本身在内,这 \(k-s\) 头奶牛(即第 \(k\) 头奶牛以及那 \(k-1-s\) 头插队位置靠前的奶牛)只要拿到礼物,其插队后的位置都会不超过 \(N-x\)

队首的前 \(N-x\) 个位置,最多只能容纳 \(N-x\) 头奶牛。如果试图挤进这前 \(N-x\) 个位置的奶牛数量 \(k-s\) 严格大于可用的位置数 \(N-x\),即 \(k-s \gt N-x \iff x \gt N - (k-s)\)。根据抽屉原理,这 \(k-s\) 头奶牛将无法全部容纳在后方的队列中,它们会在队首的前 \(N-x\) 个位置中形成内部死循环,不断轮流领礼物并相互插队,导致队首指针永远无法越过它们推进到第 \(k\) 头奶牛。

因此,第 \(k\) 头奶牛能够成功到达队首的充要条件是:对于任意的 \(x \in [0,N-1]\),均不触发上述死循环,即必须满足 \(x \le N-(k-s)\),其中 \(s\) 为前 \(k-1\) 头奶牛中满足 \(c_i \lt x\) 的奶牛总数。

参考代码
#include <iostream>
using namespace std;
const int N = (int)1e5 + 5;
int n, c[N], cnt[N];
// 判定第 $k$ 头奶牛是否能够拿到礼物
bool check(int k) {
    // 统计前 k-1 头奶牛的 c[i] 频次
    for (int i = 1; i < k; i++) {
        cnt[c[i]]++;
    }
    bool ok = true;
    int s = 0; // 记录 c[i]<x 的奶牛数量
    // 检查每一个可能的位置分割参数 x
    for (int x = 0; x < n; x++) {
        if (cnt[x] > 0) {
            // 根据抽屉原理,若 x>n-(k-s),说明奶牛无法通过该瓶颈
            if (x > n - (k - s)) {
                ok = false;
                break;
            }
            s += cnt[x];
        }
    }
    // 清理 cnt 数组
    for (int i = 1; i < k; i++) {
        cnt[c[i]] = 0;
    }
    return ok;
}
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> c[i];
    }
    // 二分最大能够拿到礼物的奶牛编号
    int l = 1, r = n, ans = 1;
    while (l <= r) {
        int m = l + (r - l) / 2;
        if (check(m)) {
            ans = m; l = m + 1;
        } else {
            r = m - 1;
        }
    }
    // 输出无法拿到礼物的奶牛数量
    cout << n - ans << "\n";
    return 0;
}