• Codeforces Round #552 (Div. 3) F. Shovels Shop (前缀和预处理+贪心+dp)


    题目:http://codeforces.com/contest/1154/problem/F

    题意:给你n个商品,然后还有m个特价活动,你买满x件就把你当前的x件中最便宜的y件价格免费,问你买k件花最少的钱是多少

    思路:首先这个特价活动就像点外卖一样满多少减多少,你可以分几次来使用同一个优惠或者不同的优惠,然后我们我们分析三个点

    1那个特价活动中x>k的我们肯定都不会使用,因为那个时候已经买满了k件

    2我们肯定是买最便宜的k件来使用特价活动

    3我们其实可以当成分开几组来使用优惠,就像外卖有些时候要分几次来点才划得来一样

    那么我们的思路就有了,我们dp[i]代表的是前i个物品的最高优惠价格,我们枚举最后一次使用特价活动是在哪个时候

    为了方便我们用几个数组分别记录一些东西

    s[i]    代表前i个的总花费

    g[i]   代表买满i个最多能减少多少个物品值   (因为活动可能有重复,买i个减x个和y个,这个时候要取最优的情况)

    dp[i] 代表的是前i个物品的最高优惠价格

    我们枚举最后一次使用活动要枚举边界在哪,所以我们要使用二重循环枚举

    这样转化一下,其实和我之前写的一篇数组分组是一样的思路了,主要还是要学会转化,建模

    #include<bits/stdc++.h>
    #define mod 1000007
    #define maxn 200001
    using namespace std;
    typedef long long ll;
    ll n,m,k;
    ll dp[maxn];
    ll s[maxn];
    ll g[maxn];
    ll a[maxn]; 
    int main(){
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+n+1);
        for(int i=1;i<=k;i++){
            s[i]=s[i-1]+a[i];//记录前缀和
        }
        for(int i=1;i<=m;i++){
            ll x,y;
            cin>>x>>y;
            if(x>k) continue;
            g[x]=max(g[x],y); //保留特价活动的最优减少数
        }
        for(int i=1;i<=k;i++){  //由前推后
            for(int j=0;j<i;j++){//枚举最后一次的特价活动位置
                dp[i]=max(dp[i],dp[j]+s[j+g[i-j]]-s[j]);
            }
        }
        cout<<s[k]-dp[k];
    } 
  • 相关阅读:
    appium工作原理
    Python文件读写模式
    Redis info 参数详解
    MySQL show status 参数详解
    Monit : 开源监控工具介绍
    Ansible(三)
    Ansible(二)
    Ansible(一)
    使用python实现后台系统的JWT认证(转)
    微信公众号-5秒内不回复测试并处理方案,顺便复习php 时间执行
  • 原文地址:https://www.cnblogs.com/Lis-/p/10724705.html
Copyright © 2020-2023  润新知