题目传送门
首先一个二分图的最大匹配=
∣
X
∣
−
m
a
x
{
∣
W
∣
−
∣
N
G
(
W
)
∣
}
(
W
∈
X
)
|X|-max\{|W|-|N_G(W)|\} (W\in X)
∣X∣−max{∣W∣−∣NG(W)∣}(W∈X)
如果一个集合
W
W
W满足了那个max,也就是再加新的
∣
N
G
(
W
)
∣
增
加
的
比
∣
W
∣
|N_G(W)|增加的比|W|
∣NG(W)∣增加的比∣W∣快。
根据HMT可知剩下的存在匹配。
然后就可以发现对于任意的
W
W
W,
N
G
(
W
)
N_G(W)
NG(W)是两段连续的区间:
[
1
,
l
]
+
[
r
,
∣
Y
∣
]
[1,l]+[r,|Y|]
[1,l]+[r,∣Y∣]组合而成。
这么看来,
∣
N
G
(
W
)
∣
=
∣
Y
∣
−
m
a
x
(
0
,
m
i
n
{
r
x
}
−
m
a
x
{
l
y
}
)
(
y
,
x
∈
W
)
|N_G(W)|=|Y|- max(0,min\{r_x\}-max\{l_y\})(y,x \in W)
∣NG(W)∣=∣Y∣−max(0,min{rx}−max{ly})(y,x∈W)
m
i
n
{
r
x
}
−
m
a
x
{
l
y
}
min\{r_x\}-max\{l_y\}
min{rx}−max{ly}其实就是
N
g
(
W
)
N_g(W)
Ng(W)中间空出来的大小,一下用
e
m
p
t
y
empty
empty表示。
把最上面的式子转换一下:
∣
X
∣
−
m
a
x
{
∣
W
∣
−
∣
Y
∣
+
e
m
p
t
y
}
(
W
∈
X
)
|X|-max\{|W|-|Y|+empty\} (W\in X)
∣X∣−max{∣W∣−∣Y∣+empty}(W∈X)
显然可以把|Y|提出来:
∣
X
∣
+
∣
Y
∣
−
m
a
x
{
∣
W
∣
+
e
m
p
t
y
}
(
W
∈
X
)
|X|+|Y|-max\{|W|+empty\} (W\in X)
∣X∣+∣Y∣−max{∣W∣+empty}(W∈X)
所以如果确定了empty的大小,就取用最大的
∣
W
∣
|W|
∣W∣去满足。
假设我们固定了empty的右边界R。
则可以选用的所有可以在W里的值都必须满足以下性质:
R
x
≥
L
R_x\geq L
Rx≥L
这样如果把所有可以选的x按照右边界的从小到大排个序:
x
1
,
x
2
.
.
.
,
x
m
x_1,x_2...,x_m
x1,x2...,xm,可以发现如果
x
i
x_i
xi被选
x
j
(
j
<
i
)
x_j(j<i)
xj(j<i)全部选上不会使答案变的更差只会变好。有人可能会问了如果选上的数组成的empty的右边界不是R,怎么办呢?
其实仔细想一想就会发现这样的情况会被更优的答案覆盖。
这样就会做了。
代码:
/*
AuThOr Gwj
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define debug_pair(A) cerr<<A.FIR<<" "<<A.SEC<<endl;
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n,m;
const int MAXN=1<<18;
int tree[MAXN*8],val[MAXN*8];
void increase(int a){
a+=MAXN-1;
tree[a]++;
val[a]=tree[a]-(a-MAXN+1);
a>>=1;
while(a){
tree[a]=tree[a<<1]+tree[(a<<1)+1];
val[a]=max(val[a<<1],val[(a<<1)+1]+tree[a<<1]);
a>>=1;
}
}
int query(int a,int b,int now=1,int l=1,int r=MAXN+1){
if(r<=a||l>=b){
return -INF;
}
if(r<=b&&l>=a){
return val[now];
}
int mid=(l+r)>>1;
return max(query(a,b,now<<1,l,mid),query(a,b,(now<<1)+1,mid,r));
}
set<mp> s;
mp sq[200000+2];
bool cmp(mp A,mp B){
return A.SEC<B.SEC;
}
int main(){
fastio;
cin>>n>>m;
memset(val,-63,sizeof(val));
rb(i,1,n)
cin>>sq[i].FIR>>sq[i].SEC,sq[i].FIR++,sq[i].SEC--;
sort(sq+1,sq+1+n,cmp);
int it=n;
int res=n;
rl(i,m,1){
while(it&&sq[it].SEC>=i){
mp now=sq[it--];
increase(now.FIR);
}
res=max(res,query(1,m+1)+i+1);
}
res=n+m-res;
res=min(res,n);
assert(res>=0);
cout<<n-res<<endl;
return 0;
}
启示:对于这类问题(比如 N G N_G NG比较特殊)不需要借助网络流来解决二分图匹配。
本文深入探讨了二分图最大匹配问题的数学原理,通过解析Hall定理的应用,提出了一个新颖的算法思路,避免了传统的网络流方法,利用离散数学中的概念实现了高效的求解。
485

被折叠的 条评论
为什么被折叠?



