hall 定理 & loj#6062. 「2017 山东一轮集训 Day2」Pair
作者:互联网
hall 定理:对于任意二分图的一部的子集 \(S\),这些点在另一部所连的点集并为 \(S'\),若有 \(|S|\le |S'|\),那么该二分图有完美匹配。
证明的话考虑归纳喽,对于一个新点,给它分配一个,那么剩下的就是 \(n-1\) 的情况了。
图论的知识要补了。。。。
回到这题。
考虑先对 \(b\) 降序排,那么对于 \(a\) 能够匹配的 \(b\) 一定是一段前缀,记 \(v_i\) 为 \(a_i\) 能匹配 \(b\) 的 \([1,v_i]\)。
考虑钦定 \([1,i]\) 为子集并,那么显然只能取 \(v_i\) 在 \([1,i]\) 内的,那么需要满足 \(\sum [v_i\le i]\le i\)。但是有时候不一定恰好钦定就有。考虑对答案有无影响。
即 \(s\le i\),显然 \(s\le i+1\),所以对答案并没有影响。
然后就是 DS 憨憨题了。
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
int rd() {
int sum=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0') {
sum=sum*10+ch-'0'; ch=getchar();
}
return sum*f;
}
const int N=(int)(1.5e+5);
int n,m,h,v[N],a[N],b[N];
bool cmp(const int &x,const int &y) {
return x>y;
}
int fd(int x) {
int l=1,r=m,res=0;
while(l<=r) {
int mid=(l+r)>>1;
if(b[mid]>=x) res=mid,l=mid+1;
else r=mid-1;
}
return res;
}
namespace BIT {
#define ls (cur<<1)
#define rs (ls|1)
int mx[N<<2],tag[N<<2];
void push_up(int cur) {
mx[cur]=max(mx[ls],mx[rs]);
}
void push_down(int cur) {
if(!tag[cur]) return ;
tag[ls]+=tag[cur]; tag[rs]+=tag[cur];
mx[ls]+=tag[cur]; mx[rs]+=tag[cur];
tag[cur]=0;
}
void build(int cur,int l,int r) {
tag[cur]=0;
if(l==r) {
mx[cur]=-l; return ;
}
int mid=(l+r)>>1;
build(ls,l,mid); build(rs,mid+1,r);
push_up(cur);
}
void upt(int cur,int l,int r,int cl,int cr,int v) {
if(cl<=l&&r<=cr) {
mx[cur]+=v; tag[cur]+=v; return ;
}
int mid=(l+r)>>1;
push_down(cur);
if(cl<=mid) upt(ls,l,mid,cl,cr,v);
if(cr>mid) upt(rs,mid+1,r,cl,cr,v);
push_up(cur);
}
}
using namespace BIT;
signed main() {
n=rd(); m=rd(); h=rd();
for(int i=1;i<=m;i++) b[i]=rd();
for(int i=1;i<=n;i++) a[i]=rd();
sort(b+1,b+1+m,cmp);
for(int i=1;i<=n;i++) {
v[i]=fd(h-a[i]);
}
build(1,0,m);
int ans=0;
for(int i=1;i<=n;i++) {
upt(1,0,m,v[i],m,1);
if(i>=m) {
int qwq=mx[1];
if(qwq<=0) ++ans;
upt(1,0,m,v[i-m+1],m,-1);
}
}
printf("%d",ans);
return 0;
}
标签:le,cur,loj,sum,Day2,mid,int,ch,6062 来源: https://www.cnblogs.com/xugangfan/p/16554636.html