您的位置:首页 > 其它

ACM: LA 4254 记住…

2016-05-19 23:27 411 查看
题目略;

题意: 现在又n个任务, 每个任务有一个时间段可以执行和它需要的量--> [ri, di,
wi]; 现在要求你
     
每个任务是可以中断的(即: 执行一段时间可以停止, 再后面某个时间再继续执行剩下的时间),
     
全部任务完毕, cpu的最大速度中的最小值. (速度: wi/执行时间).

解题思路:
     1.
我每次都不记得, 最大值中求最小的问题用二分方法可以求, 自我检讨.
     2.
用二分的方法枚举速度, 这样问题就可以转换成, 已知速度, 判断是否可以完成全部任务,
     
  这里需要用贪心的方法, 在一段时间内尽可能的完成多的任务, 所以每次我们选取执行完毕
     
  时间早的任务先做, 直到cpu不休息或者没有任务需要在这段时间做的.
     3.
在每次查找时间最早完成的任务, 可以使用线段是的方法O(logn)效率还行.

代码:

#include <cstdio>

#include <iostream>

#include <cstring>

#include <algorithm>

using namespace std;

#define MAX 10010

const int INF = (1<<29);
struct node

{

 int r, d, w;

}a[MAX];
int n, D;

int pt[4*MAX], di[2*MAX];

int timew[MAX];
bool cmp(const int &x, const int
&y) //根据时间从小到大排序

{

 int tx = x > 0 ? a[x].r :
a[-x].d;

 int ty = y > 0 ? a[y].r :
a[-y].d;

 return tx < ty;

}
inline void update(int i) //维护线段树

{

 while(i^1) //i != 1

 {

  pt[i>>1]
= a[ pt[i] ].d < a[ pt[i^1] ].d ? 
pt[i] : pt[i^1];

  i
>>= 1;

 }

}
inline int getTime(int i)

{

 return i > 0 ? a[i].r :
a[-i].d;

}
bool judge(int m)

{

 for(int i = 1; i <= n; ++i)

  timew[i] = a[i].w;

 di[2*n] = di[2*n-1];

 for(int i = 0; i < 2*n; ++i)

 {

  if(di[i] >
0)

  {

   pt[ D+di[i] ]
= di[i];

   update(D+di[i]);

  }

  else

  {

   pt[ D-di[i] ]
= 0;

   update(D-di[i]);

  }

  long long use = (long long)m*(
getTime(di[i+1]) - getTime(di[i]) );

  while(use)

  {

   int id =
pt[1];

   if(id == 0)
break;

   if(use
>= timew[id])

   {

    use
-= timew[id];

    timew[id]
= 0;

    pt[D+id]
= 0;

    update(D+id);

   }

   else

   {

    timew[id]
-= use;

    use
= 0;

   }

  }

 }

 

 for(int i = 1; i <= n; ++i)

  if(timew[i] != 0)

   return
false;

 return true;

}
int main()

{

// freopen("input.txt", "r", stdin);

 int caseNum;

 scanf("%d", &caseNum);

 while(caseNum--)

 {

  scanf("%d",
&n);

  for(int i = 1; i
<= n; ++i)

  {

   scanf("%d %d
%d", &a[i].r, &a[i].d,
&a[i].w);

   di[2*i-2] =
i;

   di[2*i-1] =
-i;

  }

  sort(di, di+2*n, cmp);

  for(D = 1; D <
n+2; D <<= 1);

  memset(pt, 0,
sizeof(pt[0])*2*D);

  a[0].d = INF;

  

  int left = 0, right =
1000*1000+5;

  int mid;

  while(true)

  {

   mid =
(left+right)/2;

   if(mid ==
left) break;

   if(judge(mid))
right = mid;

   else left =
mid;

  }

  

  printf("%d\n", mid+1);

 }

 return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: