Loading

【题解】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;
}

posted @ 2020-11-23 17:00  Moonlightsqwq  阅读(122)  评论(0编辑  收藏  举报