题意:
已知 k 个月每个月的具体信息,求满足客人需求的最小花费。
每个月的信息如下:
ci 表示第 i 个月的原材料价格
di 表示第 i 个月需要卖出的电脑数量(顾客在第 i 个月的需求)
mi 表示第 i 个月生产一台电脑的花费
pi 表示第 i 个月能生产的电脑数量
ei 表示第 i 个月可以存到下个月的电脑数
Ri 表示第 i 个月储存每单位的原材料需要的额外花费
Ei 表示第 i 个月储存每台电脑所需要第额外花费
原材料的存储量没有限制。
因为原材料没有限制,所以可以用一次for循环求出每个月的最低原材料花费。
然后利用 map 的有序性维护一个有序的数列即可(map 充当了一个仓库),每次顾客要电脑都先拿便宜的。
当map中的电脑个数比这个月的储量大的时候,将贵的电脑拿出即可。
然后就是因为电脑每存一个月其价格就会改变,所以每次存入的只是一个相对价格,便于比较。
第1个月存入的电脑与第k个月存入的电脑,其价格分别为 和
他们之间的差值为 ,为了便于比较,所以存入第 k 个月的电脑时其价格为
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <queue>
#include <functional>
#include <map>
using namespace std;
typedef long long LL;
const int N = 5e4 + 10;
LL T, k, c[N], d[N], m[N], p[N], e[N], R[N], E[N];
map<LL, LL> mp;
int main()
{
scanf("%lld", &T);
while(T--) {
scanf("%lld", &k);
for(int i=1;i<=k;i++) scanf("%lld%lld%lld%lld", &c[i], &d[i], &m[i], &p[i]);
for(int i=1;i<k;i++) scanf("%lld%lld%lld", &e[i], &R[i], &E[i]);
LL ans = 0, tot = 0, sum = 0; // tot记录库存个数, sum记录差值
for(int i=1;i<k;i++) if(c[i] + R[i] < c[i+1]) c[i+1] = c[i] + R[i];
mp.clear();
for(int i=1;i<=k;i++) {
mp[m[i]+c[i]-sum] += p[i]; tot += p[i]; // 今日电脑放入
while(!mp.empty() && d[i]){
tot -= mp.begin()->second;
if(mp.begin()->second > d[i]){
ans += (mp.begin()->first + sum) * d[i];
mp[mp.begin()->first] -= d[i];
tot += mp[mp.begin()->first];
d[i] = 0;
} else {
ans += (mp.begin()->first + sum) * mp.begin()->second;
d[i] -= mp.begin()->second;
mp.erase(mp.begin()->first);
}
}
if(d[i]) {ans = -1; break;} // 全部耗尽也无法满足需求
if(tot > e[i]){ // 库存超过限制
while(!mp.empty() && tot > e[i]){
if(tot - mp.rbegin()->second >= e[i]){
tot -= mp.rbegin()->second;
mp.erase(mp.rbegin()->first);
} else {
mp.rbegin()->second -= tot - e[i];
tot = e[i];
}
}
}
sum += E[i];
}
printf("%lld\n", ans);
}
return 0;
}