zoukankan      html  css  js  c++  java
  • BZOJ2726:任务安排(DP+斜率优化+二分)

    机器上有N个需要处理的任务,它们构成了一个序列。这些任务被标号为1到N,因此序列的排列为1,2,3...N。这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和。注意,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。
    Input
    第一行两个整数,N,S。
    接下来N行每行两个整数,Ti,Fi。
    Output
    一个整数,为所求的答案。
    Sample Input
    5 1
    1 3
    3 2
    4 3
    2 3
    1 4

    Sample Output

    153

    思路:注意是只有一台机器,所以时间是累加的,那么影响到[j,N]。所以列出方程: f[i]=min():  f[j]+(sum2[N]-sum2[j])*(sum1[i]-sum1[j]+M) 

               直接dp复杂度是O(N^2),使用效率优化:

    //b=y-kx+c; --> f[i]=(-sum1[i]*sum2[j])+(f[j]+sum1[j]*sum2[j]-sum*sum1[j]-M*sum2[j])+(M*sum+sum*sum1[j]);
    其中k之和i有关,y之和j有关,b就是f[i],c是常数:k=sum1[i],y=f[j]-sum2[N]*sum1[j]+sum2[j]*sum1[j]-sum2[j]*M;

              可以看到我们需要维护一个斜率上升的凸包,由于K=sum1[i]没有说递增,所以我们不能弹出栈顶,求的时候用二分求得凸包极值。

    注意:1,二分的时候,二分区间[0,top],0代表的是,从头到尾都选,不能忽略。

               2,每个新的i都要插入,插入当前i时,要维护斜率递增。    

               3,维护的图像的x和y分别的 y=kx+b的x和y,所以维护斜率,弹出栈尾比较斜率时,x是sum2[q[top]],而不是q[top];

    //b=y-kx+c; --> f[i]=(-sum1[i]*sum2[j])+(f[j]+sum1[j]*sum2[j]-sum*sum1[j]-M*sum2[j])+(M*sum+sum*sum1[j]);
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=1000010;
    ll sum1[maxn],sum2[maxn],f[maxn],M;
    int q[maxn],top,N;
    ll Y(int j){ return f[j]-sum2[N]*sum1[j]+sum2[j]*sum1[j]-sum2[j]*M; }
    ll getans(int i,int j){return f[j]+(sum2[N]-sum2[j])*(sum1[i]-sum1[j]+M);; }
    int main()
    {
        int i; scanf("%d%lld",&N,&M);
        for(i=1;i<=N;i++){
            scanf("%lld%lld",&sum1[i],&sum2[i]);
            sum1[i]+=sum1[i-1]; sum2[i]+=sum2[i-1];
        }
        for(int i=1;i<=N;i++){
            int L=0,R=top,ans=top;
            while(L<=R){
                int Mid=(L+R)>>1;
                if(getans(i,q[Mid])<=getans(i,q[Mid+1])) R=Mid-1,ans=Mid; else L=Mid+1;
            }
            f[i]=getans(i,q[ans]);
            while (top>0&& 1ll*(Y(q[top])-Y(q[top-1]))*(sum2[i]-sum2[q[top]])>=(Y(i)-Y(q[top]))*(sum2[q[top]]-sum2[q[top-1]]))
    top--; q[++top]=i; //while语句里不是dx的时候不是下边之间减,是方程组的sum2来减。 } printf("%lld ",f[N]); return 0; }
  • 相关阅读:
    爬虫开发9.scrapy框架之递归解析和post请求
    爬虫开发7.scrapy框架简介和基础应用
    爬虫开发6.selenuim和phantonJs处理网页动态加载数据的爬取
    爬虫开发4.三种数据解析方式
    Gym–101061A Cards(有待更新)
    GYM 101061 I. Playing with strings(有待更新)
    HDU2072 单词数
    HDU2057 A + B Again(十六进制加法运算)
    HDU2056 Rectangles
    CodeForces 992C Nastya and a Wardrobe
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9244749.html
Copyright © 2011-2022 走看看