思路:一个贪心策略就是“在不挤超过截至时间的奶牛的前提下,尽量挤奶量大的奶牛”。So我们将奶牛按截至日期从小到大排序,对于每个截至时间t,将所有截至时间为t的奶牛的奶量加入一个大根堆,只留下前t大的数,剩下的直接删去。由于priority_queue没有clear函数,所以我手写了一个堆。。。(请不要问我为什么不用小根堆,每次弹出前size()-t个数,但这样做会WA得很惨。。。)
AC Code:(代码略鬼畜,但我觉得应该没多少人看我这博客吧。。)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=10000+10; struct node{ int d,g;//d[]=deadline g[]=gain }a[N]; bool cmp(const node a,const node b){ return a.d<b.d; } int heap[N],siz; void up(int p){//向上维护大根堆 while(p>1){ //p=子节点 p/2=父节点 if(heap[p]>heap[p/2]) { //子节点大于父节点 不满足大根堆性质 //小根堆将>改为<即可 swap(heap[p],heap[p/2]); p/=2;//向上维护大根堆 } else break;//满足大根堆要求 } } void insert(int x){//向堆中插入元素 heap[++siz]=x; up(siz); } int top(){//返回堆顶元素 return heap[1]; } void down(int p){//向下维护大根堆 int s=p<<1;//儿子编号 初始为左儿子 while(s<=siz){ if(s<siz&&heap[s]<heap[s+1]) s++;//将较大的儿子换为父节点 if(heap[s]>heap[p]){ swap(heap[s],heap[p]); p=s,s=p<<1;//父节点变为较大的儿子,更新儿子编号 } else break; } } void pop(){//弹出堆顶元素 heap[1]=heap[siz--];//将堆顶元素换为堆末尾元素,然后删去末尾,避免直接删除堆顶的复杂操作 down(1); } int tmp[N],tot; int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].g,&a[i].d); sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++){ int T=a[i].d;insert(a[i].g); while(a[i+1].d==T){ insert(a[i+1].g);i++; } if(siz>T) { for(int i=1;i<=T;i++) tmp[++tot]=top(),pop(); siz=0; for(int i=1;i<=tot;i++) insert(tmp[i]); tot=0; } } int ans=0; while(siz) ans+=top(),pop(); printf("%d\n",ans); return 0; }
原文地址:https://www.cnblogs.com/Loi-Brilliant/p/9419450.html
时间: 2024-11-08 13:44:38