C. Dolce Vita(二分)

题意:给你一系列糖果,每个糖果有一个起始的价值 ai ,我们每天都会获得x元,不可积累,每种糖果每天只能买一个,每天,所有糖果都会涨价+1元,问最多能买到多少糖果?

分析:我们可以先排个序,因为贪心地想,肯定是先买最便宜的糖果更加省钱。然后如果我们买了第一个糖果 a1 ,那么达成什么条件才能买第二个呢,当然是 

所以第二个突破点,我们很自然的想到要用前缀和s[i] 来判断

最后,如何判断某种糖果可以买多少个呢?

性质 :  前多少件物品价值不超过  m(给定的价值)

//二分出前i件物品;

//从题目中可以发现  性质:和<=m,和>m;

//  s[i]<=mid; 寻找到右端点, 而下标数,就是和不超过m的最多个数;

#include <iostream>
#include <algorithm>
#include <cstring>
 
#define int long long 
 
using namespace std;
 
const int N=200010;
 
int n,m;
int a[N]; 
 
bool check(int mid)
{
	int ans=0;
	for(int i=1;i<=mid;i++)
	{
		ans+=a[i];
	}
	if(ans<=m)return true;
	else return false;
}
 
void solve()
{
	int ans=0;
	
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	
	sort(a+1,a+n+1);
	while(1)
	{
		int l=0,r=n;// 下标 
		while(l<r)
		{
			int mid=l+r+1>>1;
			//性质: <=7  的个数; 
			if(check(mid)) l=mid;
			else r=mid-1;
		}
		ans+=l;
		for(int i=1;i<=n;i++)
		{
			a[i]+=1;
		}
		if(a[1]>m)break;
	}
	cout<<ans<<endl;
}
 
signed main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
}

TLE  优化为前缀和 

#include <iostream>
#include <algorithm>
#include <cstring>

#define int long long 

using namespace std;

const int N=200010;

int n,m;
int a[N];
int s[N];

void solve()
{
	int ans=0;
	
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)
	{
		s[i]=s[i-1]+a[i];
	}
	if(a[1]>m)
	{
		cout<<ans<<endl;
		return ;
	}
	
	while(1)
	{
		int l=0,r=n;// 下标 
		while(l<r)
		{
			int mid=l+r+1>>1;
			//性质: <=7  的个数; 
			if(s[mid]<=m) l=mid;
			else r=mid-1;
		}
		ans+=l;
		for(int i=1;i<=n;i++)
		{
			a[i]+=1;
			s[i]+=i;
		}
		if(a[1]>m)break;
	}
	cout<<ans<<endl;
	return ;
}

signed main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

TLE,继续优化前缀和,因为第一次找到的那个下标之后的数一点不会再被计算到,因为每次a[i]在+1; 

#include <iostream>
#include <algorithm>
#include <cstring>

#define int long long 

using namespace std;

const int N=200010;

int n,m;
int a[N];
int s[N];

void solve()
{
	int ans=0;
	
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)
	{
		s[i]=s[i-1]+a[i];
	}
	
	while(1)
	{
		int l=0,r=n;// 下标 
		while(l<r)
		{
			int mid=l+r+1>>1;
			//性质: <=7  的个数; 
			if(s[mid]<=m) l=mid;
			else r=mid-1;
		}
		ans+=l;
		for(int i=1;i<=l;i++)
		{
			s[i]+=i;
		}
		a[1]+=1;
		if(a[1]>m)break;
	}
	cout<<ans<<endl;
	return ;
}

signed main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

还是TLE了。放弃二分,看题解。 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值