LG8444

这道题的难度不错,出题人很良心。相信大家都能看出来是贪心。题意就不用说了。

可能有人会认为是背包,但题目要的是物品越多越好,而不是价值越大越好,所以优先选择价格小的物品,这就是贪心思想了。

这题的思路也十分简单。首先将所有的 \(a_i\) 从小到大排序,找出不超过 \(w\) 的最大的 \(a_i\),因为它的价格越大,后面能换来的东西就越多。然后从 \(a_1\) 开始累加,直到总价钱超过刚刚所选的物品的价钱,输出已选的物品件数即可。

代码实现如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,a[1000001],w,ans;
long long k,t;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	cin>>w;
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)
		if(a[i]<=w)
			k=a[i];
		else
			break;
	for(int i=1;i<=n;i++)
	{
		t+=a[i];
		if(t>k)	break;
		ans++;
	}
	cout<<ans;
	return 0;
}

赛后看到出题人说降低了难度,原来是有多组询问的,本人估计数据组数 \(T\) 可能会达到 \(10^5\),如果使用如上代码会超时。发现 \(a_i\) 在排序后具有单调性,则它们的前缀和也有单调性,可以使用二分优化查询过程,把单次查询时间复杂度降到 \(O(logn)\)

注意,求前缀和的数组 \(b_i\) 要开 long long。

具体实现如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,a[1000001],w,ans;
long long k,t,b[1000001];
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	cin>>w;
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)
		b[i]=b[i-1]+a[i];
	k=upper_bound(a+1,a+n+1,w)-a;
	k--;
	k=a[k];
	ans=upper_bound(b+1,b+n+1,k)-b;
	ans--;
	cout<<ans;
	return 0;
}

在本题中效率优化不明显,因为只有一次查询。尽管在本题中两份代码都能 AC,但是如果查询次数达到 \(10^5\) 级别以上,则会有着明显的性能差异。

posted @ 2024-01-20 17:38  liyilang2021  阅读(2)  评论(0编辑  收藏  举报