codeforces 1282B2. K for the Price of One (Hard Version) (dp)
链接 https://codeforces.com/contest/1282/problem/B2
题意: 商店买东西,商店有n个物品,每个物品有自己的价格,商店有个优惠活动,当你买恰好k个东西时可以只为其中最贵的那个付款,求有限的钱中买到的最多的物品数量,你可以多次使用优惠。
思路:把所有商品的价格排序从小到大一遍,设第i个物品的价格是a[i],Sum[i]表示购买前i个物品花费的钱,作为前缀和。可以发现当你买了当第i个物品时,那么只需要支付Sum[i-k] + a [i] 即可,因为你买了当前的物品,可以赠送k-1个,那直接贪心着把小于等于当前这个物品价格的前K-1个物品直接赠送了,只需要支付a[i]费用,再支付一下sum[i-k]即可,维护整个过程sum[i] = sum[i-k] + a[i]即可。
AC代码:
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 using namespace std; 8 typedef long long ll; 9 ll mod = 1e9+7; 10 const int maxn = 2e5+10; 11 int main(){ 12 int q;cin>>q; 13 while(q--){ 14 ll n,p,k;cin>>n>>p>>k; 15 ll a[maxn]; 16 a[0] = 0; 17 for(int i = 1;i<=n;i++) cin>>a[i]; 18 sort(a+1,a+n+1); 19 ll ans = 0; 20 // 2 3 4 5 7 21 ll sum[n+1]; 22 memset(sum,0,sizeof(sum)); 23 sum[0] = 0; 24 sum[1] = a[1]; 25 for(int i = 2;i<=k;i++){ 26 sum[i] = sum[i-1] + a[i];//前k个物品价格必须都要算上,此时没有优惠卷 27 } 28 for(int i = k;i<=n;i++){ 29 sum[i] = sum[i-k] + a[i]; 30 } 31 for(int i = 0;i<=n;i++){ 32 if(p>=sum[i]) ans = i ; 33 } 34 cout<<ans<<endl; 35 } 36 return 0; 37 }