• LOJ6062 Pair


    Pair

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

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

    对于 $ 100% $ 的数据,$ 1 leq m leq n leq 150000 $;

    Hall定理

    对于二分图中的集合 X和 Y(|X|≤|Y|),任取一个 X的子集 s(s⊆X),设 Y中与 s有边相连的点集为 N(s),若 X和 Y存在完美匹配(完美匹配指的是匹配数 =|X|),则一定满足 |s|≤|N(s)|

    反之亦然,即这是该图存在完美匹配的充要条件。

    Hall定理在题目中的运用主要是为了减少判断量(不然跑网络流即可)。要想用好Hall定理,必须得发掘具体题目的性质。

    题解

    https://www.mina.moe/archives/11412

    由于a,b是独立的,因此可以看成二分图

    由于b的顺序与答案无关,因此可以先把b从小到大排个序

    设当前枚举的连续的一段a的子数列为集合X
    对于bi来说,X中与b1,b2,b3,…,bi–1相邻的点都一定与bi相邻

    因此在b中选择一个子集k,若bi是k中最大元素,那么|N(k)|就等于X中与bi相邻的点数,且|k|的最大取值就是i,需要满足|N(k)|≥|k|

    也就是说要求X中与bi相邻的点数要≥i,所以我们要维护X中与bi相邻的点数。

    注意到对于每个ai,与其相邻的点集是b的一个连续后缀,因此可以用线段树维护。

    时间复杂度 (O(nlog n))

    CO int N=15e4+10;
    int A[N],B[N];
    int val[4*N],tag[4*N];
    
    #define lc (x<<1)
    #define rc (x<<1|1)
    #define mid ((l+r)>>1)
    IN void push_up(int x){
    	val[x]=min(val[lc],val[rc]);
    }
    IN void push_down(int x){
    	if(tag[x]){
    		val[lc]+=tag[x],tag[lc]+=tag[x];
    		val[rc]+=tag[x],tag[rc]+=tag[x];
    		tag[x]=0;
    	}
    }
    void build(int x,int l,int r){
    	if(l==r) {val[x]=-l; return;}
    	build(lc,l,mid),build(rc,mid+1,r);
    	push_up(x);
    }
    void modify(int x,int l,int r,int ql,int qr,int v){
    	if(ql<=l and r<=qr) {val[x]+=v,tag[x]+=v; return;}
    	push_down(x);
    	if(ql<=mid) modify(lc,l,mid,ql,qr,v);
    	if(qr>mid) modify(rc,mid+1,r,ql,qr,v);
    	push_up(x);
    }
    #undef lc
    #undef rc
    #undef mid
    
    int main(){
    	int n=read<int>(),m=read<int>(),H=read<int>();
    	for(int i=1;i<=m;++i) read(B[i]);
    	for(int i=1;i<=n;++i) read(A[i]);
    	sort(B+1,B+m+1);
    	build(1,1,m);
    	for(int i=1;i<m;++i){
    		int j=lower_bound(B+1,B+m+1,H-A[i])-B;
    		if(j<=m) modify(1,1,m,j,m,1);
    	}
    	int ans=0;
    	for(int i=m;i<=n;++i){
    		int j=lower_bound(B+1,B+m+1,H-A[i])-B;
    		if(j<=m) modify(1,1,m,j,m,1);
    		ans+=val[1]>=0;
    		j=lower_bound(B+1,B+m+1,H-A[i-m+1])-B;
    		if(j<=m) modify(1,1,m,j,m,-1);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    C项目实践--贪吃蛇(2)
    Dos下同时执行多条命令简化操作
    C语言进入界面编程准备篇
    C项目实践--图书管理系统(4)
    C项目实践--图书管理系统(3)
    C项目实践--图书管理系统(1)
    C项目实践--图书管理系统(2)
    bzoj2302: [HAOI2011]Problem c
    bzoj3545: [ONTAK2010]Peaks
    loj#2537. 「PKUWC2018」Minimax
  • 原文地址:https://www.cnblogs.com/autoint/p/12669473.html
Copyright © 2020-2023  润新知