zoukankan      html  css  js  c++  java
  • Codeforces 1154F (DP)

    题意:有一个人去买铲子,他需要买正好k把。每把铲子有个标价,并且每把铲子最多只能被买一次。有m种优惠方案,每个优惠方案xi, yi是指如果这次恰好购买了xi把铲子,那么这次购买的铲子中最便宜的yi把将免费。问买k把铲子的最少花费。题目可以分多次购买铲子,只要购买的铲子总数是k把就可以。买过的铲子就不能再买了。

    思路:显然,我们需要先对铲子的售价排个序,然后实际上购买的铲子就是最便宜的k把铲子,因为题目中要求购买恰好k把铲子,不能多,所以不存在去购买多余的铲子去凑优惠这种方案。那么现在的问题就变成了如何选择优惠策略,使得总花费最少。设dp[i]为购买前i把铲子的最小花费,初始值为sum[i](sum[i]是排序之后的前缀和),意思是前i个铲子什么优惠都不用。我们枚举使用什么优惠去更新dp[i], dp[i] = min(dp[i - xj] + sum[i] - sum[i - xj +yj])。因为已经对花费排好序了,所以去除最小的yj个的花费是sum[i] - sum[i - xj + yj]。答案是dp[k]。

    这个题感觉很水,不知道为什么难度是2300。。。可能是题意不是很好懂把。

    代码:

    #include <bits/stdc++.h>
    #define LL long long
    #define pii pair<int, int>
    using namespace std;
    const int maxn = 200010;
    LL a[maxn], sum[maxn], dp[maxn];
    pii b[maxn];
    int main() {
    	int n, m, k;
    	scanf("%d%d%d", &n, &m, &k);
    	for (int i = 1; i <= n; i++) {
    		scanf("%lld", &a[i]);
    	}
    	for (int i = 1; i <= m; i++) {
    		scanf("%d%d", &b[i].first, &b[i].second);
    	}
    	sort(a + 1, a + 1 + n);
    	for (int i = 1; i <= n; i++)
    		sum[i] = sum[i - 1] + a[i];
    	for (int i = 1; i <= k; i++) {
    		dp[i] = sum[i];
    		for (int j = 1; j <= m; j++) {
    			if(i >= b[j].first) {
    				dp[i] = min(dp[i], dp[i - b[j].first] + sum[i] - sum[i - b[j].first + b[j].second]);
    			}
    		}
    	}
    	printf("%lld
    ", dp[k]);	 
    }
    

      

  • 相关阅读:
    CF384 div2 E. Vladik and cards
    学习Opencv Chat3
    Octave 命令积累
    Python学习-31.Python中集合的一些操作
    Python学习-30.Python中的元组(tuple)
    Python学习-29.Python中列表的一些操作
    Python学习-28.Python中的列表切片
    Python学习-27.Python中的列表(list)
    Python学习-26.Python中的三角函数
    Python学习-25.Python中的分数
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10734976.html
Copyright © 2011-2022 走看看