LOJ#6062. 「2017 山东一轮集训 Day2」Pair 题解
对每个数 \(a_i\) 求出它能匹配的 \(b_j\) 的数目,记为 \(c_i\) 。
考虑 Hall 定理,对于 \(c_i\) 的一段长度为 \(m\) 的连续子段,记 \(s_i\) 为 \(\leq i\) 的 \(c_i\) 的数目,因为 Hall 定理所以有 \(s_i \leq i\) , 并且如果满足 \(s_i \leq i\) 那么一定有完美匹配。
那么直接线段树上维护 \(s_i - i\) 的 \(\min\) 即可。
\(\Theta (n\log m)\)
code :
#include <bits/stdc++.h>
using namespace std;
template <typename T> void read(T &x){
static char ch; x = 0,ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
inline void write(int x){if (x > 9) write(x/10); putchar(x%10+'0'); }
const int N = 150005;
int n,m,h,a[N],b[N];
struct Seg{
#define lc o<<1
#define rc o<<1|1
int val[N<<2],tag[N<<2];
inline void up(int o){ val[o] = min(val[lc],val[rc]); }
inline void Tag(int o,int vv){ tag[o] += vv,val[o] += vv; }
inline void down(int o){ if (tag[o]) Tag(lc,tag[o]),Tag(rc,tag[o]),tag[o] = 0; }
inline void Build(int o,int l,int r){
if (l == r){ val[o] = l; return; }
int mid = l+r>>1; Build(lc,l,mid),Build(rc,mid+1,r),up(o);
}
int ll,vv;
inline void Add(int o,int l,int r){
if (ll <= l){ Tag(o,vv); return; }
down(o); int mid = l+r>>1; if (ll <= mid) Add(lc,l,mid); Add(rc,mid+1,r); up(o);
}
inline void add(int p,int x){ ll = p,vv = x,Add(1,0,m); }
#undef lc
#undef rc
}T;
int main(){
int i,ans = 0;
read(n),read(m),read(h);
for (i = 1; i <= m; ++i) read(b[i]); sort(b+1,b+m+1);
for (i = 1; i <= n; ++i) read(a[i]),a[i] = m - (lower_bound(b+1,b+m+1,h-a[i]) - b - 1);
T.Build(1,0,m);
for (i = 1; i <= n; ++i){
T.add(a[i],-1);
if (i >= m){
if (i > m) T.add(a[i-m],1);
if (T.val[1] >= 0) ++ans;
}
}
write(ans),putchar('\n');
return 0;
}