题意:
一个公司生产电脑,生产n个月。每个月生产时,原材料的价格、加工费的价格、生产能力、客户需求量是不同的。每个月可以多生产一些电脑,也可以多购买一些原材料储存起来,但每个月储存原材料、电脑的花费也是不一样,而且每个月储存电脑的仓库容量还不一样。问在满足客服要求的前提下,最经济的花费。
题解:
首先是要满足需求,所以我们每个月都按照最大生产力生产,可以理解为假生产,当要卖出去是才是真生产。
由于存储原材料的仓库没有容量限制,所以每个月都购买足量的原材料,卖出去时才算花费。
我们可以很容易地处理出当前的最低原料成本:,然后我们以最低原料成本全力生产。
然后是售卖,每次优先选择成本最低的电脑售卖,售卖完后,由于电脑生产多了,受到仓库大小的限制,要舍弃一些电脑,我们当然是优先舍弃成本高的电脑。
这样的生产方式,一定能尽可能地满足客户需求,而且由于是假生产,就是说,多生产的最后都不会计数,只有在卖出时才会产生花费。
那么如何快速选择最低原料成本?最低电脑成本呢?
当算到第个月时,我们当然不能对前i个月的原材料价格都加上储存原材料的费用,由于只关心最小值,假设对于第a个月和第b个月的原材料(a<b),我们比较的是和,他们的差值是就等于,显然,我们可以用一个前缀和以及set来辅助求解最小值。
同样,最低电脑成本也可以类似求解。
代码:
#include<bits/stdc++.h>
#define N 200010
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi 3.141592653589793
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%I64d",&x)
#define scc(x,y) scanf("%I64d%I64d",&x,&y)
#define sccc(x,y,z) scanf("%I64d%I64d%I64d",&x,&y,&z)
using namespace std;
LL c[N],d[N],m[N],p[N],e[N],R[N],E[N];
struct node
{
LL w,num;
bool operator < (const node z) const
{
return w==z.w? num<z.num : w<z.w;
}
};
multiset<node> s;
multiset<LL> cc;
int main()
{
LL T,n;
sc(T);
while(T--)
{
sc(n);
for (int i=1;i<=n;i++) {scc(c[i],d[i]);scc(m[i],p[i]);};
for (int i=1;i<n;i++) {sccc(e[i],R[i],E[i]);}; e[n]=0;
s.clear(); cc.clear(); LL ans=0; int fg=0; LL sum=0;
for (int i=1;i<=n;i++)
{
cc.insert(c[i]-R[i-1]);
LL t=(*cc.begin());
s.insert(node{t+R[i-1]+m[i]-E[i-1],p[i]}); sum+=p[i];
if (sum<d[i])
{
puts("-1");
fg=1; break;
}
int tot=d[i];sum-=d[i];
while(tot)
{
auto it=s.begin(); int num=(*it).num,w=(*it).w; s.erase(it);
if (num>tot)
{
s.insert(node{w,num-tot});
ans+=tot*(w+E[i-1]);
tot=0;
}else
{
tot-=num;
ans+=num*(w+E[i-1]);
}
}
while(sum>e[i])
{
auto it=s.end(); it--; int num=(*it).num,w=(*it).w; s.erase(it);
if (num<=sum-e[i]) sum-=num; else
{
s.insert(node{w,num+e[i]-sum});
sum=e[i];
}
}
R[i]+=R[i-1]; E[i]+=E[i-1];
}
if (!fg)printf("%I64d\n",ans);
}
return 0;
}