【题解】CF338E Optimize! [*easy]
考虑到最优秀的方案一定是:B 中最大的和 A 最小的匹配,次大的和次小的匹配 ...... 以此内推。
*然后容易发现,上述方案可以转化为:B 中最大的有 \(len\) 个可以和其匹配,次大的有 \(len-1\) 个可以和其匹配 ...... 以此内推。
接着考虑移动 A 的端点同时动态维护 B 每一个数的覆盖次数即可。每次 A 新增一个数就找这个数可以与那些数匹配,显然合法匹配的数在 B 中下标是连续的,因此只需要支持区间加即可。
*不妨考虑维护"覆盖次数\(-\)应有覆盖次数",这样查询的话就是查询最小值是否为 \(0\) 了。
时间复杂度 \(O(n\log n)\) 。
const int N=1.5e5+5;
int n,m,h; ll a[N],b[N];
// {{{ Segment_Tree
#define mid ((l+r)>>1)
#define lc(x) ((x)<<1)
#define rc(x) ((x)<<1|1)
ll sum[N<<2],tag[N<<2];
inline void update(int x,ll v) {sum[x]+=v,tag[x]+=v;}
inline void pushdown(int x) {update(lc(x),tag[x]),update(rc(x),tag[x]),tag[x]=0;}
void build(int x,int l,int r) {
if(l==r) return sum[x]=-(m-l+1),void();
build(lc(x),l,mid),build(rc(x),mid+1,r),sum[x]=sum[lc(x)];
}
void modify(int x,int l,int r,int R,ll val) {
if(r<=R) return update(x,val),void();
pushdown(x);
modify(lc(x),l,mid,R,val);
if(R>mid) modify(rc(x),mid+1,r,R,val);
sum[x]=min(sum[lc(x)],sum[rc(x)]);
}
// }}}
inline int find_pos(ll x) {
int l=1,r=m,ans=l;
while(l<=r) b[mid]+x>=h?ans=mid,l=mid+1:r=mid-1;
return ans;
}
int main() {
IN(n,m,h);
lep(i,1,m) IN(b[i]);
lep(i,1,n) IN(a[i]);
std::sort(b+1,b+1+n,[](ll x,ll y){return x>y;});
build(1,1,m);
int ans=0;
lep(i,1,m) if(a[i]+b[1]>=h) modify(1,1,m,find_pos(a[i]),1);
ans+=(sum[1]==0);
lep(i,m+1,n) {
if(a[i-m]+b[1]>=h) modify(1,1,m,find_pos(a[i-m]),-1);
if(a[i]+b[1]>=h) modify(1,1,m,find_pos(a[i]),1);
ans+=(sum[1]==0);
}
printf("%d\n",ans);
return 0;
}