题目链接:B2. K for the Price of One (Hard Version)
题目大意: 有p元钱,n个商品价格分别为a1 a2…an。有2种选择,第1个选择是买1个商品,第2选择是买k个商品,要求k个商品中最贵的价格不超过你手上剩余的钱。每个商品只能买1次。
解题思路: 很明显是个dp问题,首先我们按照价格从小到大给商品排序,dp[i]表示第i个商品花费的最少金额,每件商品有2种被购买的方式。当能买第k个商品时,前面的k-1个商品就不需要花钱了,那么买第x个商品时(x>k且p>ax),这时买第x-k+1个商品到第x个商品是最优的。所以可以得dp方程(x>=k)dp[x]=min(dp[x-1]+a[x],dp[x-k]+a[x])。当x<k时只能是买一个商品,所以dp[x]=dp[x-1]+a[x]。
代码:
#include <bits/stdc++.h>
using namespace std;
#define maxn 200010
#define ll long long
ll a[maxn];
ll dp[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,p,k;
scanf("%d%d%d",&n,&p,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
sort(a+1,a+1+n);
dp[0]=0;
for(int i=1;i<k;i++){
dp[i]=dp[i-1]+a[i];
}
for(int i=k;i<=n;i++){
dp[i]=min(dp[i-1]+a[i],dp[i-k]+a[i]);
}
ll ans=1;
ll out=0;
while(ans<=n){
if(dp[ans]<=p)out=max(out,ans);
ans++;
}
printf("%d\n",out);
}
return 0;
}