体检 排序 排队问题

NKOJ 2425 体检

时间限制 : 10000 MS 空间限制 : 165536 KB

问题描述

 开学了,学校要求你进行入学体检。你到了校医务室门口,发现有好多学生在排队,人数还在不断增加。
  有多个体检项目要做。每个项目都有很多人在排队。队伍的长度在随着时间变长。该选哪一个队伍排队呢?这成了一个问题。你要安排一下体检顺序,尽可能早的完成所有项目的体检。

输入格式

第一行一个整数n,表示要体检的项目数量 接下来n行,每行表示一个体检项目。每行两个整数a和b,描述该项目的情况:
1.如果你在第0时刻加入了这只队伍,需要等待a秒钟才能完成该项目的检查。
2.当你不在这个队伍里,随时间队伍会变得越来越长,等待的时间每秒钟会增加b秒。

输出格式

一个整数表示你完成体检最短需要花费的时间。 结果可能很大,所以请mod (365×24×60×60)再打印出结果

样例输入 1

5
1 2
2 3
3 4
4 5
5 6

样例输出 1

1419

样例输入 2

7
5 2
2 27
9 5
7 16
2 3
14 10
13 9

样例输出 2

331466

提示

【样例1说明】
你按以下次序体检.
1.在第一个队伍中花了1秒
2.在第二个队伍中花了5秒
3.在第三个队伍中花了27秒
4.在第四个队伍中花了169秒
5.在第五个队伍中花了1217秒 所以总时间是1419秒
【数据范围】
对于50%的数据有:1<=n<=1000 0<=a,b<=30000
对于100%的数据有:1<=n<=100000 0<=a,b<=50000


很久之前的题目了。由于最近做到一道感觉类似的题NKOJ4231 理发时间,所以拿出来写一写。

这道题的棘手之处在于,每一个决定都会直接影响到未来。且由于数据范围太大以及排队顺序可以不按照输入数据来(废话,按照输入数据来的话模拟即可),因此我们无法使用费用提前计算

(说这些是想到了另一道题:NKOJ1047 任务安排,这道题是费用提前计算)

正向思维遇到了障碍:我们难以从现有条件出发找到最优解。那么不妨采用反向思维:从已经找到解的假定出发,寻找最优解需要满足的条件(这点和那道题是类似的)。

分析:

显然的一个贪心,如果在之前都是最优方案的情况下,如果要选两个队伍依次排队,那么我们优选排完队后耗时较少的方案。

假定之前已经找到了最优安排方案,耗时为t,现在有两个队伍(a1,b1)和(a2,b2)。不妨设(a1,b1)较优。那么有:

b1×t+a1+(a1+t)×b2+a2<b2×t+a2+(a2+t)×b1+a1

化简后可以得到:
a1×b2<a2×b1

与t无关,那么我们可以对此进行排序了。对于排好序的方案,先去排序号小的队。求答案时模拟即可。

#include<stdio.h>
#include<algorithm>
#define ll long long
#define mod 31536000
#define MAXN 100005
using namespace std;
struct node{ll a,b;}stu[MAXN];
bool cmp(node x,node y){return x.a*y.b<x.b*y.a;};
int N;
ll Ans;

int main()
{
    int i;

    scanf("%d",&N);
    for(i=1;i<=N;i++)scanf("%lld%lld",&stu[i].a,&stu[i].b);
    sort(stu+1,stu+N+1,cmp);
    for(i=1;i<=N;i++)Ans=(Ans+Ans*stu[i].b+stu[i].a)%mod;

    printf("%lld",Ans);
}

总结:

比较最优解与其他解,通过数学演算从而找出最优解满足的条件,是这道题关键的分析方法。这点在一些斜率优化题也里有体现。
这种题还有一个特点,就是现在的操作只对后面未进行的操作有影响(这道题没怎么体现出,详见NKOJ4231 理发时间)。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值