CF #610Div2 B2.K for the Price of One (Hard Version) (dp解法 && 贪心解法)

题目大意:刚开始有 p 块钱,商店有 n 件物品,你每次可以只买一件付那一件的钱,也可以买 k 件只付最贵那件的钱,问你最多能买几件 (k<=n<=2e5)

首先我们要明确,如果你买了这一件商品,那么你一定买了比这件商品价格低的所有商品,因为这样买花的钱才会更少,方法才是最优的。

解法一:这道题用 背包dp 解应该是最直观的,先排序一下,状态要么由前一件转移过来,要么由前 k 件转移过来,即 dp[i] = min(dp[i-1]+a[i],dp[i-k]+a[i])然后我们只要找到买哪一件之前花的钱 <=p 就好了。
 1 #include <iostream>
 2 #include <algorithm>
 3 using namespace std;
 4 const int N = 2e5 + 5;
 5 int t, n, p, k, ans, a[N], dp[N];
 6 int main()
 7 {
 8     ios::sync_with_stdio(false);
 9     cin >> t;
10     while (t--)
11     {
12         cin >> n >> p >> k;
13         for (int i = 1; i <= n; i++)
14             cin >> a[i];
15         sort(a + 1, a + n + 1);
16         ans = 0;
17         for (int i = 1; i <= n; i++)
18         {
19             dp[i] = dp[i - 1] + a[i];
20             if (i >= k)
21                 dp[i] = min(dp[i], dp[i - k] + a[i]);
22             if (dp[i] <= p)
23                 ans = max(ans, i);
24         }
25         cout << ans << ‘\n‘;
26     }
27     return 0;
28 }// 93ms

解法二:

其实很多人最开始想到的都是贪心,我们不难发现,尽量使用第二个技能永远是最佳的,一旦第二个技能不能再使用,剩下的钱我们就一个一个去买前面价格低的。所以我们只要枚举前 k-1 个单买( >=k 个的话我们只要用第二个技能买一定更划算),后面的我们全部用第二个技能买就行了,维护可以买到的数量最大值就好了。

 1 #include <iostream>
 2 #include <algorithm>
 3 using namespace std;
 4 const int N = 2e5 + 5;
 5 int t, n, p, k, a[N];
 6 int main()
 7 {
 8     ios::sync_with_stdio(false);
 9     cin >> t;
10     while (t--)
11     {
12         cin >> n >> p >> k;
13         for (int i = 0; i < n; i++)
14             cin >> a[i];
15         sort(a, a + n);
16         int now = 0, pre = 0, ans = 0, cnt = 0;
17         for (int i = 0; i < k; i++)
18         {
19             now = pre;
20             cnt = i;                         // 单买前 cnt 个商品,目前花费 now 元
21             if (now > p)
22                 break;
23             for (int j = i + k - 1; j < n; j += k)        // 第 i 件之后的全部用二技能买
24             {
25                 now += a[j];
26                 if (now <= p)
27                     cnt += k;
28                 else
29                     break;
30             }
31             ans = max(ans, cnt);
32             pre += a[i];
33         }
34         cout << ans << ‘\n‘;
35     }
36     return 0;
37 }// 108ms

原文地址:https://www.cnblogs.com/Satan666/p/12098318.html

时间: 2024-10-09 22:45:15

CF #610Div2 B2.K for the Price of One (Hard Version) (dp解法 && 贪心解法)的相关文章

K for the Price of One

B. K for the Price of One (Hard Version) 赛时失手推错了规律... 这个题不是单调递增的 但是它有一个规律:当买同样多的东西时,优先买便宜的 所以我们可以求出买 i 个东西时最便宜的价格 sort(a+1,a+n+1); for(int i=1;i<=k-1;++i) dp[i]=a[i]+dp[i-1]; for(int i=k;i<=n;++i) dp[i]=dp[i-k]+a[i]; 因为考虑到 n 只有2e5的范围,所以把每一个\(dp[i]\)

CF gym 101933 K King&#39;s Colors —— 二项式反演

题目:http://codeforces.com/gym/101933/problem/K 其实每个点的颜色只要和父亲不一样即可: 所以至多 i 种颜色就是 \( i * (i-1)^{n-1} \),设为 \( f(i) \),设恰好 i 种颜色为 \( g(i) \) 那么 \( f(i) = \sum\limits_{j=0}^{i} C_{i}^{j} * g(j) \) 二项式反演得到 \( g(i) = \sum\limits_{j=0}^{k} (-1)^{k-j} * C_{k}

CF 1039D You Are Given a Tree &amp;&amp; CF1059E Split the Tree 的贪心解法

1039D 题意: 给你一棵树,要求对给定链长于 k = 1, 2, 3, ..., n,求出最大的链剖分. 1059E 题意: 给你一棵带权树,要求对于一组给定的 L, W 求出最小完全竖链剖分满足每条链点数不超过 L,权值和不超过 W. 显然两题是有共同点的,就是让我们求满足一定条件的树的最值链剖分. 比较暴力的可以尝试用 DP 计数,但是我不想深入 DP,因为方程比较复杂,思考起来不太容易. 很巧的是,这两题可以用相似的贪心思想来做. 在思考具体细节之前,需要明确贪心的主要思想:在从下往上

LeetCode1005 K次取反后最大化的数组和(贪心+Java简单排序)

题目: 给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次.(我们可以多次选择同一个索引 i.) 以这种方式修改数组后,返回数组可能的最大和. 示例 1: 输入:A = [4,2,3], K = 1输出:5解释:选择索引 (1,) ,然后 A 变为 [4,-2,3]. 示例 2: 输入:A = [3,-1,0,2], K = 3输出:6解释:选择索引 (1, 2, 2) ,然后 A 变为 [3,1,0,2]

Codeforces Round #610 (Div. 2) a/b/c

题目 传送门 A Temporarily unavailable   standard input/output 1 s, 256 MB  给一个线段ab, 问除去 c点圆心半径r覆盖的 线段多长,如果圆在线段外 直接输出 ab 长度就行, 若在线段内 则输出cout << max(b-a-max((min(c+r,b)-max(a,c-r)),0), 0) ,迷糊的话纸上画下大概就能明白.B1 K for the Price of One (Easy Version) , B2 K for

HDU #2191 买米问题 多重背包及其优化

Description 问题描述以及测试样例在这:HDU#2191 思路 这道题其实就是多重背包问题,即有 N 种物品和一个容量为 V 的背包,第 i 种物品最多有 n[i] 件可用,每件费用是 c[i] ,价值是 w[i] ,求哪些物品装入背包可以使得这些物品的费用总和不超过背包容量,且价值总和最大.在这道题中,背包容量是经费,费用是每种米的价格,价值是每种米的重量,求用给定的经费买米,使得买到米的总重量最大,注意经费是可以剩余的. 其实多重背包问题和完全背包问题非常相似,只不过前者的物品是有

Codeforces Round #610 (Div. 2) 题解

Temporarily unavailable K for the Price of One (Hard Version) Petya and Exam Temporarily unavailable \[ Time Limit: 1 s\quad Memory Limit: 256 MB \] 直接计算出 \([c-r, c+r]\) 在 \([a, b]\) 中的范围有多大,然后减掉就可以了. view #include <map> #include <set> #includ

Code+第二次月赛div1题解(转)

T1 ####算法一 暴力枚举所有可能的$a_2$并递推判断.复杂度$O(r \times k)$,预期得分10分. ####算法二 $a_k$可以表示为$a_1$与$a_2$的线性组合.使用递推计算出系数,并暴力枚举所有可能的$a_2$判断.复杂度$O(r+k)$,预期得分30分. ####算法三 暴力枚举所有可能的$a_2$并使用矩阵乘法判断.复杂度$O(r \times \log(k))$,预期得分50分. ####算法四 与算法二类似,使用递推计算出系数,此时可以发现可能的$a_2$满足

CF 1110 D/E

CF 1110 D. Jongmah 题目大意:给你?\(n\)个瓷砖,每块瓷砖上有一个数字?\(a_i,(1\leq a_i\leq m)\).你可以将三个有连续数字?\((比如3,4,5)\)的瓷砖或者三个数字相同?\((比如7,7,7)\)的瓷砖组成一个三元组.每个瓷砖只能用一次.问最多可以得到多少个三元组.? 比赛的时候好像全场A穿,然而并没有想到 (TAT. 一开始想到\(DP\),但是?觉得状态数太大:于是想了奇奇怪怪的贪心,但是都能找到反例. 这道题的关键是要发现一个性质:同一位置