LOJ「2017 山东一轮集训 Day2」Pair

题目描述

给出一个长度为 n 的数列{ a i }和一个长度为 m 的数列{ b i },求{ a i }有多少个长度为 m 的连续子数列能与{ b i }匹配。

两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当且仅当它们的和不小于 h

输入格式

第一行三个数字 n , m , h
第二行有 m 个数字 b 1 , b 2 , , b m ​​ 。
第三行有 n 个数字 a 1 , a 2 , , a n ​ 。

输出格式

输出一个数字,{ a i }有多少个长度为 m 的连续子数列能与 { b i }匹配。

思路

将b排序,ai与b的匹配当做一条边,b的每一元素当做点,问题转化为判断aL到aR的线段与b的点的完美匹配是否存在。

代码

#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
const int maxn=150005,INF=0x3f3f3f3f;
int N,M,H,w,ans;
int a[maxn],b[maxn];
inline int read() {
    int ret=0,f=1;char ch=getchar();
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') f=-f;
    for (; isdigit(ch); ch=getchar()) ret=ret*10+ch-48;
    return ret*f;
}
inline int Find(int x) {
    x=H-x;
    if (b[1]>=x) return 1;
    if (b[M]<x) return M+1;
    int L=1,R=M;
    while (L<=R) {
        int mid=L+R>>1;
        if (b[mid]>=x&&b[mid-1]<x) return mid;
        if (b[mid]>=x) R=mid-1;
        else L=mid+1;
    }
}
struct Seg{
#define ls (o<<1)
#define rs (o<<1|1)
#define mid (L+R>>1)
    int minv[maxn<<2],laz[maxn<<2];
    inline void pushup(int o) {minv[o]=min(minv[ls],minv[rs]);}
    inline void pushdown(int o) {
        if (laz[o])
            minv[ls]+=laz[o],laz[ls]+=laz[o],
            minv[rs]+=laz[o],laz[rs]+=laz[o];
        laz[o]=0;
    }
    void Build(int o,int L,int R) {
        if (L==R) {minv[o]=-L;return;}
        Build(ls,L,mid),Build(rs,mid+1,R);
        pushup(o);
    }
    void Updata(int o,int L,int R,int ql,int qr,int dat) {
        if (ql<=L&&R<=qr) {minv[o]+=dat,laz[o]+=dat;return;}
        if (qr<L||R<ql) return;
        pushdown(o);
        Updata(ls,L,mid,ql,qr,dat),Updata(rs,mid+1,R,ql,qr,dat);
        pushup(o);
    }
    int Query(int o,int L,int R,int ql,int qr) {
        if (ql<=L&&R<=qr) return minv[o];
        if (ql<L||R<ql) return INF;
        pushdown(o);
        return min(Query(ls,L,mid,ql,qr),Query(rs,mid+1,R,ql,qr));
    }
#undef ls
#undef rs
#undef mid
}T;
int main() {
    N=read(),M=read(),H=read();
    for (int i=1; i<=M; i++) b[i]=read();
    for (int i=1; i<=N; i++) a[i]=read();
    sort(b+1,b+1+M);
    T.Build(1,1,M);
    for (int i=1; i<=M; i++) if ((w=Find(a[i]))<=M) T.Updata(1,1,M,w,M,1);
    if (T.Query(1,1,M,1,M)>=0) ans++;
    for (int i=M+1; i<=N; i++) {
        if ((w=Find(a[i]))<=M) T.Updata(1,1,M,w,M,1);
        if ((w=Find(a[i-M]))<=M) T.Updata(1,1,M,w,M,-1);
        if (T.Query(1,1,M,1,M)>=0) ans++;
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zj_js_zxb/article/details/80530251