洛谷链接:
K for the Price of One (Hard Version) - 洛谷
(本题还有一个easy version,用这个代码也能过)
思路:
思路是贪心和dp递推。
不难发现,要买数量最多的商品,最优解必定是拿走最便宜一部分商品(包括买的和送的),所以从便宜的到贵的逐个遍历,如果当前数量<k,必须全买,如果>=k,挑最贵的免单。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
int t, n, p, k; //询问次数,商品数,硬币数,捆绑购买数
int cost[maxn];
int dp[maxn]; //dp[i]表示买下前i个物品需要的最少钱数
int main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> t;
while(t--){
cin >> n >> p >> k;
for(int i=1; i<=n; i++)
cin >> cost[i];
sort(cost+1, cost+n+1);
for(int i=1; i<=n; i++){
//如果商品数 < k,无法免单,必须全买
if(i<k) dp[i] = dp[i-1] + cost[i];
//如果商品数 >= k,可以免单,贪心地选最贵的k-1个免单
else dp[i] = dp[i-k] + cost[i];
}
int ans = 0;
for(int i=1; i<=n; i++){ //扫描一遍,找出能买的最多的物品数
if(dp[i] <= p) ans = i;
}
cout << ans << '\n';
}
}