当前位置: 代码迷 >> 综合 >> 【数据结构】【平衡树】【贪心】HDU6408 From ICPC to ACM
  详细解决方案

【数据结构】【平衡树】【贪心】HDU6408 From ICPC to ACM

热度:126   发布时间:2023-09-27 06:39:59.0

题意:

题意非常的鬼畜。。。
你经营着一家电脑公司,需要满足一些客户的需♂求。

每个月,你可以购买电脑配件(误),每单位价格为cici
每个月需要制造didi台电脑,每制造一台电脑,需要一单位的电脑配件,然后外加mimi的人工费。而且每个月最多制造pipi台电脑。

然后电脑和配件都可以储存。
从第i个月存到第i+1i+1个月,最多储存eiei台电脑,每储存一单位配件代价为RiRi,每储存一台电脑的代价为EiEi

求满足所有条件的最小代价。(不能满足输出-1)

分析:

很简单的贪心模拟题。。。

然而我考场上写爆了、。。。一个最近经常犯的sb错误。。。更改变量后,想访问其原来的值,结果直接访问了更改后的。。。。

啊啊啊啊啊啊

其实真心水

一个贪心的思路:每次造电脑,都用之前的,代价最小的didi个。

因此要把之前的代价排序。。。

然而其实这个排序是一定的。(即可以预处理出来,不用一边模拟一边排序)

首先,由于配件是没有上限的,所以可以预处理得出:在每天造电脑用的配件的代价。这个很容易就能预处理出来,无非就是设当前最小的为minpminp,然后每一天和当天的cici取min,这一天后minp+=Riminp+=Ri

方便起见,可以把材料代价和造电脑的人力费mimi合起来。

然后呢,再设当天的总代价为mi+j=i,j<kEjmi+∑j=i,j<kEj

这样表示的话,在第x天出厂(给客户)时,要另外减去j=x,j<kEj∑j=x,j<kEj

这样有什么好处呢,很容易发现,因为减去的值只与出厂当天有关,所以这样一来每天造电脑的总代价就是一个定值了!

是个定值就可以直接排序了!

然后可以得到:在任意一天造电脑的代价排名。

现在只需要支持以下操作:找出当前存在的,代价最小的didi个值,找出当前存在的,代价最小的eiei个值(后面的会被删去),以及有序插入每天的代价(以及当天能造出的电脑数)。

这不就是平衡树板题么。。。

每个节点存储:其代价,以及能制造的总数。还有其子节点全部制造完的总代价。

然后就可以水过去啦。。。。要注意ei=0ei=0的时候要特判。。。

我的代码考场上为了卡常,对无解情况直接O(n)O(n)排出来,其实可以不用。。(考场上TLE是因为没有加ei=0ei=0的特判)

#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;elsey->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);elseRotate(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);}
}
  相关解决方案