zoukankan      html  css  js  c++  java
  • bzoj 2726: [SDOI2012]任务安排

    Description

    机 器上有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

    HINT

    Source

    这个题一开始想着去处理一个人等了多长时间

    然后就会发现等的时间是和前面分了多少批有关的,这样的话我们需要用二维状态表示到这个点,前面分了多少批

    这样暴力n^3会很萎

    这时候我们会回想起一个叫做修车的题目,他对于每个点的处理相当于是这个点让后面的人多等了多久

    那我们可以通过同样的方式思考,每分了一批其实就是让后面的所有人多等了一个S的时间,其余的并不影响

    那么我们可以推出一维的状态

    f[i]=min(f[j]+s*(F[n]-F[j])+T[i]*(F[i]-F[j]));

    对于前百分之60的数据,T为正数,满足决策单调性,可以二分栈,但我懒得打了,就在codevs上AC了一个弱化版的n^2;

    斜率优化+CDQ在下面

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<set>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<ctime>
    #define lson num<<1
    #define rson num<<1|1
    #define int long long
    using namespace std;
    typedef long long ll;
    const int N=100050;
    int gi()
    {
      int x=0,flag=1;
      char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
      return x*flag;
    }
    int f[N],t[N],F[N],s,n;
    int cal(int j,int i){
    	return f[j]+s*(F[n]-F[j])+t[i]*(F[i]-F[j]);
    }
    main()
    {
    	n=gi(),s=gi();
    	for(int i=1;i<=n;i++) t[i]=gi()+t[i-1],F[i]=gi()+F[i-1];
    	for(int i=1;i<=n;i++){
    		f[i]=cal(0,i);
    		for(int j=1;j<i;j++){
    			f[i]=min(f[i],cal(j,i));
    		}
    	}
    	printf("%lld",f[n]);
    }
    

    我们来推一推斜率方程:

    f[j]+s*(F[n]-F[j])+T[i]*(F[i]-F[j)<=f[k]+s*(F[n]-F[k])+T[i]*(F[i]-F[k]);
    f[j]+s*F[n]-s*F[j]+T[i]*F[i]-T[i]*F[j]<=f[k]+s*F[n]-s*F[k]+T[i]*F[i]-T[i]*F[k];
    f[j]-s*F[j]-T[i]*F[j]<=f[k]-s*F[k]-T[i]*F[k];
    令Y(j)=f[j]-s*F[j];
    令X(j)=F[j];
    则变为:
    Y(j)-T[i]*X(j)<=Y(k)-T[i]*X(k);
    T[i]*(X(k)-X(j))<=Y(k)-Y(j);
    若X(k)>=X(j):T[i]<=(Y(k)-Y(j))/(X(k)-X(j));
    若X(k)<=X(j);T[i]>=(Y(k)-Y(j))/(X(k)-X(j));
    因为F值都是正的,所以X(k)>=X(j);横坐标单调;
    所以T[i]<=(Y(k)-Y(j))/(X(k)-X(j));
    然而斜率T[i]不是单调的

    然后我就不会做了

    上面的点的做法就是在瞎哔哔;

    下面介绍线的神教:

    方程:f[j]+s*(F[n]-F[j])+T[i]*(F[i]-F[j])

    展开:

    f[j]+s*F[n]-s*F[j]+T[i]*F[i]-T[i]*F[j]

    整理:

    f[j]-s*F[j]+s*F[n]+T[i]*F[i]*T[i]-F[j]*T[i]

    利用线的套路转变:

    b=f[j]-s*F[j];k=F[j];x=T[i],s*F[n]+F[i]*T[i]为常数

    然后我们发现斜率k是满足单调性的,而横坐标x根据题意有负数是不满足单调性的。

    这时候我们可以直接应用货币兑换的CDQ分治(把斜率和横坐标都不当成单调的搞):

    在左边维护斜率单调构造半平面交

    在右边维护横坐标单调进行决策转移

    具体分析请参考货币兑换的博客,上面有详解

    附上代码:

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<set>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<ctime>
    #define lson num<<1
    #define rson num<<1|1
    #define int long long
    using namespace std;
    typedef long long ll;
    const int N=300050;
    int gi()
    {
      int x=0,flag=1;
      char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
      return x*flag;
    }
    struct data {int k,x,b;int id;}g[N],q[N],p[N];
    bool cmp(data a,data b){
        return a.x<b.x;
    }
    int f[N],F[N],T[N],s,n;
    void solve(int l,int r){
        if(l==r) return;
        int mid=(l+r)>>1,l1=l,l2=mid+1,head=1,tail=0;
        for(int i=l;i<=r;i++){
            if(g[i].id<=mid) p[l1++]=g[i];
            else p[l2++]=g[i];
        }
        for(int i=l;i<=r;i++) g[i]=p[i];
        solve(l,mid);
        for(int i=l;i<=mid;i++){
            while(head<tail&&(g[i].k-q[tail-1].k)*(q[tail-1].b-q[tail].b)>=(q[tail].k-q[tail-1].k)*(q[tail-1].b-g[i].b))
                tail--;
            q[++tail]=g[i];
        }
        //sort(g+mid+1,g+r+1,cmp);
        for(int i=mid+1;i<=r;i++){
            while(head<tail&&q[head].k*g[i].x+q[head].b>=q[head+1].k*g[i].x+q[head+1].b)
                head++;
            f[g[i].id]=min(f[g[i].id],q[head].k*g[i].x+q[head].b+T[g[i].id]*F[g[i].id]+s*F[n]);
            g[i].b=f[g[i].id]-s*F[g[i].id];
        }
        solve(mid+1,r);l1=l,l2=mid+1;
        for(int i=l;i<=r;i++){
            if(l2>r||(l1<=mid&&g[l1].k>=g[l2].k)) p[i]=g[l1++];
            else p[i]=g[l2++];
            }
        for(int i=l;i<=r;i++) g[i]=p[i];
    }
    main()
    {
        n=gi(),s=gi();
        for(int i=1;i<=n;i++){
            T[i]=gi()+T[i-1];
            F[i]=gi()+F[i-1];
            g[i].id=i,g[i].k=-F[i],g[i].x=T[i];
        }
        for(int i=1;i<=n;i++) f[i]=s*F[n]+T[i]*F[i],g[i].b=f[i]-s*F[i];
        sort(g+1,g+n+1,cmp);solve(1,n);
        printf("%lld",f[n]);
    }
    

      

  • 相关阅读:
    jmeter参数化
    安卓稳定性压测工具_monkey环境搭建(简易)
    安卓开发环境搭建
    linux环境下禅道搭建
    Elasticsearch 开源版、基础版、黄金版、铂金版功能差异
    防火墙与127.0.0.1
    基于x-pack的ES用户管理(认证)
    elasticsearch-keystore 命令简单解释
    Elasticsearch核心技术与实战-学习笔记
    程序设计随想
  • 原文地址:https://www.cnblogs.com/qt666/p/6524321.html
Copyright © 2011-2022 走看看