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;
}