zoukankan      html  css  js  c++  java
  • 2020 ICPC North America Championship Problem G

    Problem Link

    statement

    有数组A与数组B,你可以选择A的某个数与B的某个数搭配,每次搭配需要满足数组中每个数不重复选且(a_i+b_ileq s),令(d_i=abs(a_i-b_i)),(D=max(d_1,d_2,..,d_n)),求完成n组匹配能得到的最小的D。

    input

    (nleq 2 imes 10^5)
    (a_i,b_i,sleq 10^9)

    idea

    啊,这题竟然比赛时没做出来quq...实在没想到怎么贪。
    首先看到D是一堆数的最大,又要求D的最小,最大的最小与最小的最大很明显是二分答案的信号。我们二分每个D,对于数组A每个数x对应的B数组的数y需要满足

    egin{cases} &yleq s-x\ &yleq D+x\ &ygeq x-d end{cases}

    我们将A,B数组排序,按照以上不等式,每个A数组对应可选的B数组为一段序列,我们将以上序列排序后从左到右枚举B数组每个数。首先,如果当前的数在一段序列内,一定要拿,因为每次匹配都是相同的贡献,你留着不拿,给后面的数拿并不会增加贡献。其次,如果有多个序列段能进行匹配,一定要拿r(序列右端点)最小的,因为后面的数l一定比当前数大,所以l不能产生约束,但是当前拿r最小的,可能可以给后面更多的数得到匹配。所以就这么贪心地拿,在$O(nlog n)$内可以完成匹配。而二分答案次数为$O(log s)$,故总时间复杂度为$O(nlog nlog s)$。

    代码

    /*************************************************************************
    	> File Name: 3.cpp
    	> Author: Knowledge_llz
    	> Mail: 925538513@qq.com 
    	> Blog: https://blog.csdn.net/Pig_cfbsl 
    	> Created Time: 2020/10/5 14:20:58
     ************************************************************************/
    #include<bits/stdc++.h>
    #define For(i,a,b) for(register int i=(a);i<=(b);++i)
    #define pb push_back
    #define pr pair<int,int>
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define LL long long
    using namespace std;
    int read(){
    	char x=getchar(); int u=0,fg=0;
    	while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
    	while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
    	return fg?-u:u;
    }
    const int maxx=2e5+10;
    int a[maxx],b[maxx],n,p,q,s;
    struct cmp{
    	bool operator () (const pr &a,const pr &b)const{
    		return a.se>b.se;
    	}
    };
    queue<pr>Q;
    priority_queue<pr,vector<pr>,cmp>que;
    bool check(int d){
    	int tmp=0;
    	while(!Q.empty()) Q.pop();
    	while(!que.empty()) que.pop();
    	For(i,1,p){
    		int x=lower_bound(b+1,b+q+1,a[i]-d)-b,lim=min(a[i]+d,s-a[i]);
    		int y=upper_bound(b+1,b+q+1,lim)-b-1;
    		if(x<=y) Q.push(mk(x,y));
    	}
    	For(i,1,q){
    		while(!Q.empty() && Q.front().fi<=i){
    			que.push(Q.front());
    			Q.pop();
    		}
    		while(!que.empty()){
    			int r=que.top().se;
    			que.pop();
    			if(r<i)	continue; 
    			++tmp;
    			break;
    		}
    		if(tmp>=n) return tmp>=n;
    	}
    	return tmp>=n;
    }
    		
    int main()
    {
    //	freopen("input.in","r",stdin);
    //	freopen("output.out","w",stdout);
    	n=read(); p=read(); q=read(); s=read();
    	For(i,1,p) a[i]=read();
    	For(i,1,q) b[i]=read();
    	sort(a+1,a+p+1);
    	sort(b+1,b+q+1);
    	int l=0,r=1e9,mid,ans=-1;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(check(mid)){ r=mid-1; ans=mid; }
    		else l=mid+1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    解决使用vim-go插件时候保存go代码导致设置好的折叠消失的问题
    golang中从一个日期开始往后增加一段时间
    linux kernal oom killer 学习
    awk学习笔记
    FlexMonkey实战
    如何阅读一本书-读书笔记
    Oracle性能问题sql调优脚本集
    了解ORACLE培训OCA-OCP-OCM课程表
    Sublime Text 3设置笔记
    【总结】AngularJs学习总结
  • 原文地址:https://www.cnblogs.com/Knowledge-Pig/p/13772043.html
Copyright © 2011-2022 走看看