【2018杭电多校Round8 L】From ICPC to ACM

题意

一共有k个月
第i个月原材料价格为c_i ,制造一台电脑要花费一个原材料和m_i元,最多能生产p_i台电脑,客户需求d_i台,
当月卖出的原材料和电脑不收取存储费用,没用完的原材料和电脑可以留到下个月
第i个月能存放e_i台电脑价格为E_i,存放原材料容量无限价格为R_i
求满足每个月客户需求的最小成本

分析

  1. 因为原材料存储容量无限,如果这个月的c_i加上R_i+1小于c_i+1,那么c_i+1 = c_i+R_i,以此可以得到每个月最便宜的原材料价格。
    进而,我们可以换成原材料不要钱,制造一台电脑的费用是c_i+m_i。
    进而,我们可以考虑,尽可能多的制造电脑(依据产能),然后卖出客户需求数量,再扔掉超出下个月仓库限制的数量,制造电脑不要钱,只有卖出的时候才算钱,如果扔掉就相当于没有制造过。
    所有制造出来的电脑每个月的成本都会加上一个E_i,所以考虑优先卖掉最便宜的电脑,扔掉最贵的电脑。
  2. 解决插入元素,删除最小的若干元素,最大的若干元素
    使用multiset,元素为一个二元组<价格,数量> ,每次删除头尾的若干元素就好
    到第i个月,当月存储成本是E_i,有些已经在仓库里的元素其实还加上了∑(k=begin→i-1)E_k,用前缀和思想,我们可以维护一个值add,表示第2个月到当前的所有的存储费用总和,那么插入元素的时候成本可以减去这个add,以后所有元素求费用的时候都加上add

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 5e4+5;
const int inf = 0x3fffffff;
multiset< pair<long long,int> >st;
int c[N],d[N],m[N],p[N],e[N],R[N],E[N],n;
long long ans,add,tot;
int main(){
    int _;scanf("%d",&_);
    while(_--){
	st.clear();ans=0LL,add=0,tot=0;;
	scanf("%d",&n);
	c[0] = inf;
	for(int i=1;i<=n;i++) scanf("%d%d%d%d",&c[i],&d[i],&m[i],&p[i]);
	for(int i=2;i<=n;i++) scanf("%d%d%d",&e[i],&R[i],&E[i]);
	e[n+1] = 0;
	int flag = 0;
	for(int i=1;i<=n;i++){
	    c[i] = c[i]<c[i-1]+R[i]?c[i]:c[i-1]+R[i];
	    add+=E[i];
	    st.insert(make_pair(c[i]+m[i]-add,p[i]));tot+=p[i];
	    if(tot<d[i]){ flag = 1;break;}
	    tot-=d[i];
	    auto it = st.begin();
	    while(d[i]>(it->second)){
		d[i]-=(it->second);
		ans+=it->second*1LL*(add+(it->first));
		it = st.erase(it);
	    }
	    if(d[i]){
		int x = it->first,y = it->second-d[i];
	        ans+=d[i]*1LL*(add+x);
		st.erase(it);
		st.insert(make_pair(x,y));
	    }
	    if(tot>e[i+1]){
		int dec = tot-e[i+1];
		tot=e[i+1];
		auto it = st.end();it--;
		while(dec>it->second){
		    dec-=it->second;
		    it=st.erase(it);it--;
		}
		if(dec){
		    int x = it->first,y = it->second-dec;
		    st.erase(it);
		    st.insert(make_pair(x,y));
		}
	    }
	}
	if(flag == 1){puts("-1");}
	else {printf("%lld\n",ans);}
    }
}

posted @ 2018-08-16 10:37  Greenty  阅读(133)  评论(0编辑  收藏  举报