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\) 级别以上,则会有着明显的性能差异。
还是菜。