[关闭]
@Junlier 2018-11-05T14:35:09.000000Z 字数 1899 阅读 1608

[CQOI2012]模拟工厂 题解(搜索+贪心)

题解
阅读体验:https://zybuluo.com/Junlier/note/1327574

链接题目地址:洛谷P3161 BZOJ P2667
这个题练一练综合思想还是不错的。。。(然而蒟蒻不会啊)

做法

肯定是在能完成某些订单的情况下使自己生产力越高越好是吧(一个大致的贪心方向)
但是我们不知道自己到底应该怎么去决定提高生产力时间
那么换个角度,不从时间来看,从订单上来看

贪心

我们假设一定要完成订单
那么应该如何贪心选时间提升生产力呢,当然是在能满足所有订单的基础上尽量多地提高生产力
那么对于订单,我们都会得到方程:(设为完成订单时的生产力,为距离订单的时间,为用来提升生产力的时间,是订单需求量)

对所有我们一定要完成的订单一个一个完成,每次完成一个订单时对它之后的每一个订单我们都解这么一个方程,得到尽可能的休息时间,那么这样子一定是对的吧

然后可以想到

上面是我们都想完成,现在不同了,我们可以放弃一些订单
再看数据范围:?,那不就暴力枚举状态选还是不选啊
然后对于上面那个方程,如果无解肯定这种计划是不行的
然后直接用求根公式会得到:

算一下时间复杂度:很对呀,那就做完了
枚举状态虽可以直接枚举,但也可以搜是吧,那我们就叫他搜索了

给出代码

哼哼~压行是看代码人的噩梦,是写代码者的美梦(虽然笔者只稍稍压行了。。。

  1. #include<bits/stdc++.h>
  2. #define il inline
  3. #define rg register
  4. #define ldb double
  5. #define lst long long
  6. #define rgt register int
  7. #define N 20
  8. #define M 100050
  9. using namespace std;
  10. const int Inf=1e9;
  11. il lst MAX(rg lst x,rg lst y){return x>y?x:y;}
  12. il lst MIN(rg lst x,rg lst y){return x<y?x:y;}
  13. il int read()
  14. {
  15. int s=0,m=0;char ch=getchar();
  16. while(!isdigit(ch)){if(ch=='-')m=1;ch=getchar();}
  17. while( isdigit(ch))s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
  18. return m?-s:s;
  19. }
  20. int n,UP;
  21. lst Ans,Res;
  22. int sgn[N],top;
  23. struct DD{lst tt,gv,gt;}ljl[N];
  24. bool cmp(const int&a,const int&b){return ljl[a].tt<ljl[b].tt;}
  25. il void Solve(rgt Zt)
  26. {
  27. top=Res=0;
  28. for(rgt i=1;i<=n;++i)
  29. if(Zt&(1<<(i-1)))sgn[++top]=i,Res+=ljl[i].gt;
  30. if(Res<Ans)return;
  31. sort(&sgn[1],&sgn[top+1],cmp);
  32. rg lst pdc=1,rest=0;
  33. rg bool flag=true;
  34. for(rgt i=0;i<top;++i)
  35. {
  36. rg lst nd=0,brk=Inf;
  37. for(rgt j=i+1;j<=top;++j)
  38. {
  39. nd+=ljl[sgn[j]].gv;
  40. rg lst tm=ljl[sgn[j]].tt-ljl[sgn[i]].tt;
  41. rg lst b=pdc-tm,c=nd-rest-pdc*tm;
  42. if(b*b-4*c<0){flag=false;break;}//delta
  43. rg lst x=(sqrt(b*b-4*c)-b)/2;
  44. brk=MIN(brk,x);
  45. }pdc+=brk;
  46. rest+=pdc*(ljl[sgn[i+1]].tt-ljl[sgn[i]].tt-brk)-ljl[sgn[i+1]].gv;
  47. if(!flag||brk<0||rest<0){flag=false;break;}
  48. }if(flag)Ans=MAX(Ans,Res);
  49. }
  50. int main()
  51. {
  52. n=read(),UP=(1<<n);
  53. for(rgt i=1;i<=n;++i)
  54. ljl[i]=(DD){read(),read(),read()};
  55. for(rgt i=1;i<UP;++i)Solve(i);
  56. return printf("%lld\n",Ans),0;
  57. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注