题意:
题意非常的鬼畜。。。
你经营着一家电脑公司,需要满足一些客户的需♂求。
每个月,你可以购买电脑配件(误),每单位价格为
每个月需要制造
台电脑,每制造一台电脑,需要一单位的电脑配件,然后外加
的人工费。而且每个月最多制造
台电脑。
然后电脑和配件都可以储存。
从第i个月存到第
个月,最多储存
台电脑,每储存一单位配件代价为
,每储存一台电脑的代价为
求满足所有条件的最小代价。(不能满足输出-1)
分析:
很简单的贪心模拟题。。。
然而我考场上写爆了、。。。一个最近经常犯的sb错误。。。更改变量后,想访问其原来的值,结果直接访问了更改后的。。。。
啊啊啊啊啊啊
其实真心水
一个贪心的思路:每次造电脑,都用之前的,代价最小的 个。
因此要把之前的代价排序。。。
然而其实这个排序是一定的。(即可以预处理出来,不用一边模拟一边排序)
首先,由于配件是没有上限的,所以可以预处理得出:在每天造电脑用的配件的代价。这个很容易就能预处理出来,无非就是设当前最小的为 ,然后每一天和当天的 取min,这一天后 。
方便起见,可以把材料代价和造电脑的人力费 合起来。
然后呢,再设当天的总代价为
这样表示的话,在第x天出厂(给客户)时,要另外减去
这样有什么好处呢,很容易发现,因为减去的值只与出厂当天有关,所以这样一来每天造电脑的总代价就是一个定值了!
是个定值就可以直接排序了!
然后可以得到:在任意一天造电脑的代价排名。
现在只需要支持以下操作:找出当前存在的,代价最小的 个值,找出当前存在的,代价最小的 个值(后面的会被删去),以及有序插入每天的代价(以及当天能造出的电脑数)。
这不就是平衡树板题么。。。
每个节点存储:其代价,以及能制造的总数。还有其子节点全部制造完的总代价。
然后就可以水过去啦。。。。要注意 的时候要特判。。。
我的代码考场上为了卡常,对无解情况直接 排出来,其实可以不用。。(考场上TLE是因为没有加 的特判)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 50010
using namespace std;
typedef long long ll;
ll c[MAXN],d[MAXN],p[MAXN],e[MAXN],m[MAXN],R[MAXN],E[MAXN];
int id[MAXN];
ll pre[MAXN];
pair<ll,ll> cost[MAXN];
int k;
struct node *NIL;
struct node{
node *ch[2],*fa;
ll val,sum,num,pri;
ll hjb;
bool Dir(){
return this==fa->ch[1];
}
void setchild(node *x,int d){
ch[d]=x;
if(x!=NIL)
x->fa=this;
}
void pushup(){
//pushdown();
//if(x->ch[0]!=NIL)x->ch[0]->pushdown();
//if(x->ch[1]!=NIL)x->ch[1]->pushdown();
totprice=ch[0]->totprice+ch[1]->totprice+pri*num;
sum=ch[0]->sum+ch[1]->sum+num;
}
}tree[MAXN],*root,*ncnt;
node * Newnode(node *x,int val){
x->val=id[val];
x->ch[0]=x->ch[1]=x->fa=NIL;
x->sum=x->num=p[val];
x->pri=pre[val]+m[val];
x->totprice=x->pri*x->num;
return x;
}
void Rotate(node *x){
node *y=x->fa;
//y->pushdown(),x->pushdown();
int d=x->Dir();
if(y==root)
root=x,x->fa=NIL;
else
y->fa->setchild(x,y->Dir());
y->setchild(x->ch[!d],d);
x->setchild(y,!d);
y->pushup();
}
void Splay(node *x,node *rt){
//x->pushdown();
while(x->fa!=rt){
node *y=x->fa;
if(y->fa==rt){
Rotate(x);
break;
}
if(x->Dir()==y->Dir())
Rotate(y);
else
Rotate(x);
Rotate(x);
}
x->pushup();
}
void Ins(node *&root,int val,int key){
if(root==NIL){
root=Newnode(++ncnt,key);
return ;
}
node *y=root;
int d;
while(1){
y->sum+=p[key];
y->totprice+=p[key]*(pre[key]+m[key]);
d=(y->val)<val;
if(y->ch[d]==NIL)
break;
y=y->ch[d];
}
y->setchild(Newnode(++ncnt,key),d);
y->pushup();
Splay(y->ch[d],NIL);
}
void init(){
for(int i=1;i<=k+1;i++)
c[i]=d[i]=m[i]=p[i]=e[i]=R[i]=E[i]=pre[i]=0;
root=NIL;
ncnt=NIL;
}
node * find_kth(node *x,int k){
if(x->ch[0]->sum >= k)
return find_kth(x->ch[0],k);
k-=x->ch[0]->sum;
if(k<=x->num)
return x;
k-=x->num;
return find_kth(x->ch[1],k);
}
bool check(){
ll sumx=0;
for(int i=1;i<=k;i++){
sumx+=p[i];
if(sumx<d[i])
return 1;
sumx-=d[i];
sumx=min(sumx,e[i]);
}
return 0;
}
int main(){
NIL=&tree[0];
NIL->ch[0]=NIL->ch[1]=NIL->fa=NIL;
root=ncnt=NIL;
int t;
SF("%d",&t);
while(t--){
SF("%d",&k);
init();
for(int i=1;i<=k;i++)
SF("%I64d%I64d%I64d%I64d",&c[i],&d[i],&m[i],&p[i]);
for(int i=1;i<k;i++)
SF("%I64d%I64d%I64d",&e[i],&R[i],&E[i]);
if(check()){
PF("-1\n");
continue;
}
ll minp=c[1];
for(int i=1;i<=k;i++){
minp=min(minp,c[i]);
m[i]+=minp;
minp+=R[i];
}
for(int i=k;i>=1;i--){
pre[i]=pre[i+1]+E[i];
cost[i]=make_pair(pre[i]+m[i],i);
}
sort(cost+1,cost+1+k);
for(int i=1;i<=k;i++)
id[cost[i].second]=i;
ll ans=0;
for(int i=1;i<=k;i++){
if(p[i]!=0)
Ins(root,id[i],i);
if(d[i]!=0){
node *x=find_kth(root,d[i]);
Splay(x,NIL);
ll res=x->ch[0]->totprice;
ll d1=d[i];
d[i]-=x->ch[0]->sum;
x->ch[0]=NIL;
res+=d[i]*x->pri;
if(d[i]==x->num){
root=x->ch[1];
root->fa=NIL;
}
else{
x->num-=d[i];
x->pushup();
}
res-=pre[i]*d1;
ans+=res;
}
if(i==k||root->sum <= e[i])
continue;
if(e[i]==0){
root=ncnt=NIL;
continue;
}
node *x=find_kth(root,e[i]);
Splay(x,NIL);
e[i]-=x->ch[0]->sum;
x->num=e[i];
x->ch[1]=NIL;
x->pushup();
}
PF("%I64d\n",ans);
}
}