zoukankan      html  css  js  c++  java
  • CF1409E Two Platforms

    传送门

    分析

    本题的两个平台能否接住水滴仅与水滴的横坐标有关,所以纵坐标可以直接扔掉不管
    小贪心:对于每一个水珠,显然,两个平台必须不能重合( 除非两个平台的总长度大于 (n) ),而且,平台若想要最大化接住的水滴数,显然平台的一个端点必然要接到至少一个水珠

    那么,本题的解法就显然易见了:我们可以直接枚举每一个水珠的横坐标,计算以该水珠为起点的一个平台长度内一共能接到多少水珠,最后输出两个互不重合的平台能接到的水珠总数的最大值

    Solution

    显然,如果单纯的枚举与判断是至少要 (O(nk)) 的,会 T 得飞起,所以,我们考虑优化

    我们要做的是找到区间长度为 (k) 内的数的个数,并不用计算数值大小,那么,我们可以进行离散化处理

    对于每一段长度为 (k) 的区间,我们可以用利用前缀和预处理得到

    如:

    sort(a+1,a+n+1);
    m=unique(a+1,a+n+1)-a-1;
    for(int i=1;i<=n;i++)
    {
          b[lower_bound(a+1,a+m+1,x[i])-a]++;//正常离散化
    }
    for(int i=1;i<=n;i++)
    {
          pre[i]=pre[i-1]+b[i];//记录前缀和
    }
    for(int i=1;i<=n;i++)
    {
          fg[i]=pre[upper_bound(a+i+1,a+m+1,a[i]+k)-a-1]-pre[i-1];
          //设平台起点横坐标为 i ,查找最后一个横坐标小于 i+k 的水珠的位置,利用前缀和做差快速求出该区间内一共有多少水珠
    }
    

    所以,我们可以再利用线段树,将另一块平台所能接到的最大水珠数量求出
    node *rot=New(1,n);
    for(int i=1;i<=m;i++)
    {
          ans=max(ans,rot->qry(upper_bound(a+i+1,a+m+1,a[i]+k)-a,m)+fg[i]);
          //这里的fg[i]表示了点第一块平台所能接到的最大水珠数量
          //用线段树查询该平台末端以后的区间内,另一块平台所能覆盖到的最大水珠数量
    }
    

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<math.h>
    #define ll long long
    using namespace std;
    
    const ll maxn=2e5+10;
    ll t,n,m,k,ans;
    ll x[maxn],y[maxn],a[maxn],b[maxn],pre[maxn],fg[maxn];
    
    struct node
    {
    	ll v,l,r;
    	node *ls,*rs;
    	
    	inline void pushup()
    	{
    		v=max(max(v,ls->v),rs->v);
    	}
    	inline bool inrange(ll L,ll R)
    	{
    		return (L<=l)&&(r<=R);
    	}
    	inline bool outofrange(ll L,ll R)
    	{
    		return (l>R)||(r<L);
    	}
    	inline ll qry(ll L,ll R)
    	{
    		if(inrange(L,R)) return v;
    		if(outofrange(L,R)) return 0;
    		
    		return max(ls->qry(L,R),rs->qry(L,R));
    	}
    };
    
    node Mem[maxn<<1];
    node *pool=Mem;
    
    inline node *New(ll L,ll R)
    {
    	node *u=pool++;
    	u->l=L;
    	u->r=R;
    	
    	if(L==R)
    	{
    		u->v=fg[L];
    		u->ls=u->rs=NULL;
    	}
    	else
    	{
    		ll M=(L+R)>>1;
    		u->ls=New(L,M);
    		u->rs=New(M+1,R);
    		u->pushup();
    	}
    	return u;
    }
    
    int main(void)
    {
    	scanf("%lld",&t);
    	
    	while(t--)
    	{	
    		ans=0;
    		
    		scanf("%lld%lld",&n,&k);
    		
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%lld",&x[i]);
    			a[i]=x[i];
    		}
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%lld",&y[i]);
    		}
    		
    		for(int i=0;i<=n;i++) b[i]=pre[i]=fg[i]=0;
    		sort(a+1,a+n+1);
    		m=unique(a+1,a+n+1)-a-1;
    		for(int i=1;i<=n;i++)
    		{
    			b[lower_bound(a+1,a+m+1,x[i])-a]++;
    		}
    		for(int i=1;i<=n;i++)
    		{
    			pre[i]=pre[i-1]+b[i];
    		}
    		for(int i=1;i<=n;i++)
    		{
    			fg[i]=pre[upper_bound(a+i+1,a+m+1,a[i]+k)-a-1]-pre[i-1];
    		}
    		
    		node *rot=New(1,n);
    			
    		for(int i=1;i<=m;i++)
    		{
    			ans=max(ans,rot->qry(upper_bound(a+i+1,a+m+1,a[i]+k)-a,m)+fg[i]);
    		}
    		
    		printf("%lld
    ",ans);
    	}
    	
    	return 0;
    }
    

    另外,要注意 (lower_bound)(upper_bound) 的使用

  • 相关阅读:
    python_day06(ip代理池)
    二叉树的层次遍历之队列的使用
    推荐系统实战笔记 1.1什么是推荐系统
    牛顿法求平方根可拓展
    java LinkedHashMap实现LRUCache缓存
    交换两个变量常规四种做法
    交换两个变量之移位交换法
    推荐系统实战笔记01--前言
    Ubuntu 14.04更新为国内阿里源解决apt-get install无法执行的问题
    求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
  • 原文地址:https://www.cnblogs.com/jd1412/p/13701006.html
Copyright © 2011-2022 走看看