hall 定理,即对于二分图一部的子集 $S$,每个点在另一部连得边的并集 $S'$,有 $|S| \le |S'|$,则该二分图有完美匹配。
$$[1,r],r\le could_r$$
$$[l,r],l-1\le could_{l-1},r\le could_{r}$$
$$r-(l-1)\le could_{r}-could_{l-1}$$
$$could_i-i\ge0$$
实际上 $b$ 升序/顺序没有影响。处理麻烦或简单而已。
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cmath> #include <queue> #include <map> #define ll long long using namespace std; int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } ll lrd() { ll f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } #define ls (cur<<1) #define rs (ls|1) const int N=(int)(1.5e5+5); int mi[N<<2],tag[N<<2]; int n,m,h,a[N],b[N]; void push_up(int cur) { mi[cur]=min(mi[ls],mi[rs]); } void push_down(int cur) { if(!tag[cur]) return ; tag[ls]+=tag[cur]; tag[rs]+=tag[cur]; mi[ls]+=tag[cur]; mi[rs]+=tag[cur]; tag[cur]=0; } void build(int cur,int l,int r) { mi[cur]=0x3f3f3f3f; if(l==r) return mi[cur]=-l,void(); int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); push_up(cur); } void update(int cur,int l,int r,int cl,int cr,int v) { if(cl<=l&&r<=cr) { tag[cur]+=v; mi[cur]+=v; return ; } push_down(cur); int mid=(l+r)>>1; if(cl<=mid) update(ls,l,mid,cl,cr,v); if(cr>mid) update(rs,mid+1,r,cl,cr,v); push_up(cur); } int 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); build(1,1,m); int ans=0; // a[i]+b[i]>=h a[i]-h>=b[i] for(int i=1;i<=m;i++) { int p=lower_bound(b+1,b+1+m,h-a[i])-b; if(p<=m) update(1,1,m,p,m,1); } ans+=mi[1]>=0; for(int i=m+1;i<=n;i++) { int p=lower_bound(b+1,b+1+m,h-a[i-m])-b; if(p<=m) update(1,1,m,p,m,-1); p=lower_bound(b+1,b+1+m,h-a[i])-b; if(p<=m) update(1,1,m,p,m,1); ans+=mi[1]>=0; } printf("%d",ans); return 0; }