Bonuses on a Line

B. Bonuses on a Line

给出线段上的点坐标,一个人在原点,可以走t的路程,问最多可以经过几个点。朴素想到贪心,后面感觉贪心情况太复杂,策略不一定对。可以分成4种情况,只往左,只往右,先左再右,先右再左。显然,问题可以转化。将负数段,正数段分别存储。相当于在两个数组里选点数尽可能多的两段,使得其中一段的长度*2+另一段的长度<=t。对于后两种情况,当一个端点定下来的时候,另一端的极限就定了。对于前两种情况也就相当于一端定在0,查找另一端极限的方式是,减去已经用掉的部分。用upper_bound查找剩下的部分可以经过的最多点数令就可以了。

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<vector>
#include<functional>
using namespace std;
typedef long long LL;
inline LL read()
{
    LL kk=0,f=1;
    char cc=getchar();
    while(cc<'0'||cc>'9'){if(cc=='-')f=-1;cc=getchar();}
    while(cc>='0'&&cc<='9'){kk=(kk<<1)+(kk<<3)+cc-'0';cc=getchar();}
    return kk*f;
}
const int maxn=1000222;
LL a[maxn],l,r,mid,t,n,ans;
vector<LL>fi,se;
void gao()
{
	ans=upper_bound(fi.begin(),fi.end(),t)-fi.begin();//只向一边走
	ans=max(ans,(LL)(upper_bound(se.begin(),se.end(),t)-se.begin()));
	for(int i=0;i<se.size();++i)//枚举右端点
	{
		if(t>se[i])//先往左再往右,
		{
			LL kk=(t-se[i])/2;//左边两倍
			LL num=upper_bound(fi.begin(),fi.end(),kk)-fi.begin();
			ans=max(i+num+1,ans);
		}
		if(t>se[i]*2)//先右再左
		{
			LL kk=t-2*se[i];//右边两倍
			LL num=upper_bound(fi.begin(),fi.end(),kk)-fi.begin();
			ans=max(i+num+1,ans);
		}
	}
	
}
int main()
{
	n=read();t=read();
	for(int i=1;i<=n;++i)
	{
		a[i]=read();
		if(a[i]<0)fi.push_back(-a[i]);//负数段
		else se.push_back(a[i]);//正数段
	}
	sort(fi.begin(),fi.end());
	gao();
	
	printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值