题意:

一个公司生产电脑,生产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;
}