Hall 定理
理论部分
原定理
对于一个二分图,两个条件等价:
- 存在一种方案,使得所有左部点都能顺着边匹配到一个右部点,且每个右部点只匹配一次。
- 左边任意取 \(k\) 个点,这些点能到达的右部点一定大于等于 \(k\) 个。
充分性:已经有 \(k\) 个右部点匹配了,只会多不会少。
必要性:如果只有一个左部点一定成立,否则删去一对匹配点,仍然满足条件。
扩展 1
对于一个二分图,两个条件等价:
- 存在一种方案,使得第 \(i\) 个左部点都能顺着边匹配到 \(h_i\) 个右部点,且每个右部点只匹配一次。
- 左边任意取 \(k\) 个点 \(\set{p_1,p_2,\cdots,p_k}\),这些点能到达的右部点一定大于等于 \(\sum_{i=1}^k h_{p_i}\) 个。
证明:将第 \(i\) 个左部点点拆分成 \(h_i\) 个单点,下同原定理。
扩展 2
对于一个二分图,两个条件等价:
- 存在一种方案,使得不超过 \(a\) 个左部点不能顺着边匹配到一个右部点,且每个右部点只匹配一次。
- 左边任意取 \(k\) 个点,这些点能到达的右部点一定大于等于 \(k-a\) 个。
证明:开 \(a\) 个虚右部点,和左边所有点连边,
则新图中原定理条件 1 等价于条件 1,则新图中原定理条件 2 等价于条件 2。
题目
P3488
由于对应鞋码不相交的两端区间可以合并,没有附加条件,所以我们只考虑相交情况。
直接对着 Hall 定理抄答案,设 \(i\) 号脚有 \(p_i\) 个人,
需要判断每一个子段 \(\sum_{i=l}^r p_i\le (\min\set{n,r+d}-l+1)\)。
等价于 \(\sum_{i=l}^r p_i-(\min\set{n-d,r}-l+1)=\sum_{i=l}^r ({p_i-[i\le n-d]})\le d\)。
等价于对于初始 \(p_i=-[i\le n-d]\) 的数组直接去修改,求最大子段和小于等于 \(d\)。
一次修改操作,左面的不会有影响,右面的需要分讨。
我们需要找到右面第一个前缀和比当前这个地方小的,再往右都不会受影响。
于是我们可以开两个线段树,
一个记录前缀和,负责每次修改和线段树二分;
一个记录最大子段和,根据指令进行区间加和,全局求 \(\max\)。
线段树二分是什么?
就是先用线段树性质去分区间,如果左边有就返回左边,否则右边有就返回右边,否则返回没有。
//线段树二分示例代码
//这里是查找区间第一个小于 base 的元素,k 数组存储的是区间 min。
int query(int i,int l,int r,int L,int R,int base){
if(k[i]>base) return -1;
if(l!=r) pushdown(i,l,r);
if(l==L&&r==R){
if(l==r) return l;
int mid=(l+r)>>1;
if(k[ls]<base) return query(i<<1,l,mid,l,mid,base);
if(k[rs]<base) return query(i<<1|1,mid+1,r,mid+1,r,base);
}
if(R<=mid) return query(i<<1,l,mid,L,R,base);
if(L>mid) return query(i<<1|1,mid+1,r,L,R,base);
int tmp=query(i<<1,l,mid,L,mid,base);
return (tmp==-1)?query(i<<1|1,mid+1,r,mid+1,R,base):tmp;
}

浙公网安备 33010602011771号