Description
商店里有 nn 双鞋,每双鞋都有一个价格。你要买其中的严格 k 双。每双鞋只能被买一次。
你每次购买可以挑选剩余鞋中的任意一个子集来购买集合中所有的鞋。
有 m 种套餐,第 ii 种套餐代表如果一次性购买xi 双鞋则其中最便宜的 yi双免费。
这 m 种套餐每种都可以用任意次。
现在请求出买严格 k 双鞋的最小花费。
Input
第一行是三个整数 n,m,k
一行 n 个整数描述每双鞋的价格
下面 m 行,每行两个整数 xi,yi描述一个套餐。
Output
输出一行一个整数代表答案。
- 题目说到只能从小到大免费
奸诈精明的商人…所以为了方便操作,直接先排序 - 在确定优惠策略后肯定是靠右买更好(最右边的鞋不管怎么排都会给钱)
- so,先预处理出买x双鞋最多能省多少钱
- 然后直接买买买(误),等数量达到优惠条件就状态转移(如此一般…)
上代码!!
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#define il inline
#define re register
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int n, m, k;
int dp[maxn];
//dp[i]: 买i双鞋最少花费
//cut[i]: 买i双免费几双
int a[maxn], cut[maxn];
int main() {
scanf("%d%d%d", &n, &m, &k);
for(re int i = 1; i <= n; ++i) scanf("%d", &a[i]);
sort(a+1, a+n+1);
for(re int i = 2; i <= n; ++i)
a[i] += a[i-1];//花费从小到大排
int x, y;
memset(cut, 0, sizeof(cut));
for(re int i = 1; i <= m; ++i) {
scanf("%d%d", &x, &y);
cut[x] = max(cut[x], y);
//省的越多越好
}
for(re int i = 1; i <= k; ++i) {
dp[i] = 0x3f3f3f3f;
for(re int j = 0; j < i; ++j) {
//前面预留j个不参与套餐
dp[i] = min(dp[i], dp[j]+a[i]-a[j+cut[i-j]]);
}
}
printf("%d\n", dp[k]);
return 0;
}