一本通提高1607 任务安排2

【题目描述】

有 N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。从时刻 0 开始,任务被分批加工,执行第i个任务所需的时间是 Ti。另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。

一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。也就是说,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数 Ci 。

请为机器规划一个分组方案,使得总费用最小。

【输入】

第一行是 N。第二行是 S

下面 N 行每行有一对正整数,分别为 Ti和 Ci ,表示第 i 个任务单独完成所需的时间是 Ti 及其费用系数 Ci 。

【输出】

一个数,最小的总费用。

【输入样例】

5
1
1 3
3 2
4 3
2 3
1 4

【输出样例】

153

【提示】

数据范围与提示:

对于全部数据,1≤N≤10^4,0≤S≤50,1≤Ti,Ci≤100。

————————————————————————————————————————————

网上大多数都是按照一本通提高篇做的,都是从1到n枚举。我的是逆序枚举的,偏偏做的过程中出了一点点问题,没得参考了,只能自己调。幸好只是小问题!

原先,做过这个题,不过可能是数据较水的问题用任务安排1的代码过了,这次算是正式补上斜率优化这一块!

这个和其他不同的是,就是逆序枚举,还要维护单调性,比较不爽!

————————————————————————————————————————————

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
int n,s;
int f[maxn],sc[maxn],smt[maxn];
int q[maxn],l,r;
ll y(int a)
{
    return f[a]+sc[a]*smt[a];
}
long double get_xl(int a,int b)
{
    return (long double)(y(b)-y(a))/(smt[b]-smt[a]);
}
int main()
{
    scanf("%d%d",&n,&s);
    for(int t,c,i=1;i<=n;++i)
    {
        scanf("%d%d",&smt[i],&sc[i]);
        smt[i]+=smt[i-1];
        sc[i]+=sc[i-1];
    }
    for(int i=n;i>=0;--i)
    {
        while(l<r&&get_xl(q[l],q[l+1])>=sc[i])++l;
        f[i]=f[q[l]]+(sc[q[l]]-sc[i])*smt[q[l]]+(sc[n]-sc[i])*s;
        while(l<r&&get_xl(q[r-1],q[r])<=get_xl(q[r],i))--r;
        q[++r]=i;
    }
    cout<<f[0]<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/gryzy/p/14380675.html