• BZOJ2726 [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
     
    正解:cdq分治+斜率优化
     
    解题报告:大体同上一篇cash的题解相同,但是有一个特别奇妙的地方(网络流好题 修车),
    对于每一次分组,我们不是通过前面分了多少组来算它的费用,而是把在这里分组而对后面产生
    的影响记在自己身上(因为在这里分一组之后,后面的每一组的时间都要加s+t),
    所以我们能得出转移方程:dp[i]=min{dp[j]+s*(f[n]-f[j])+t[i]*(f[i]-f[j])}(t数组记得
    是时间的前缀和,f数组记得是费用的前缀和);然后再把它拆开:dp[j]+s*f[n]-s*f[j]+t[i]*f[i]-t[i]*f[j]
    s乘f[n]是一个定值,t[i]*f[i]只跟i有关,我们把它们视为常数,然后式子变成dp[j]+s*f[j]-t[i]*f[j];
    dp[j]+s*f[j]只跟j有关,视为b,t[i]当为x,f[j]当为k,然后就成为了kx+b的形式,再套上cdq维护
    x与k的单调性就可以用斜率优化了,时间复杂度O(nlogn)。
     
     
    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <string>
    #include <cstring>
    #include <algorithm>
    #define RG register
    #define int long long
    #define ld long double
    #define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    const int N = 400000;
    
    using namespace std;
    
    int gi(){
    	char ch=getchar();int x=0,q=0;
    	while(ch<'0' || ch>'9') {if (ch=='-') q=1;ch=getchar();}
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return q? (-x) : x;
    }
    
    int n,s;
    int t[N],f[N],dp[N];
    
    struct date{
    	double k,x,b;int t;
    	bool operator < (const date &a) const{
    		return x<a.x;
    	}
    }g[N],st[N],p[N];
    
    inline void cdq(int l,int r){
    	if (l==r) return;
    	int mid=(l+r)>>1,p1=l,p2=mid+1,head=1,tail=0;
    	for (RG int i=l; i<=r; ++i)
    		if (g[i].t<=mid) p[p1++]=g[i];
    		else p[p2++]=g[i];
    	for (RG int i=l; i<=r; ++i) g[i]=p[i];
    	cdq(l,mid);
    	for (RG int i=l; i<=mid; ++i){
    		while(head<tail && (ld)(st[tail-1].b-st[tail].b)*(g[i].k-st[tail-1].k)>=(ld)(st[tail-1].b-g[i].b)*(st[tail].k-st[tail-1].k)) --tail;
    		st[++tail]=g[i];
    	}
    	sort(g+mid+1,g+r+1);
    	for (RG int i=mid+1; i<=r; ++i){
    		while(head<tail && st[head].k*g[i].x+st[head].b>=st[head+1].k*g[i].x+st[head+1].b) ++head;
    		dp[g[i].t]=min((double)dp[g[i].t],st[head].k*g[i].x+f[n]*s+st[head].b+t[g[i].t]*f[g[i].t]);
    		g[i].b=dp[g[i].t]-s*f[g[i].t];
    	}
    	cdq(mid+1,r);p1=l,p2=mid+1;
    	for (RG int i=l; i<=r; ++i)
    		if (p2>r || (p1<=mid && g[p1].k>=g[p2].k)) p[i]=g[p1++];
    		else p[i]=g[p2++];
    	for (RG int i=l; i<=r; ++i) g[i]=p[i];
    	return;
    }
    
    main(){
    	File("work");
    	n=gi(),s=gi();
    	for (RG int i=1; i<=n; ++i) t[i]=gi()+t[i-1],f[i]=gi()+f[i-1];
    	for (RG int i=1; i<=n; ++i){
    		dp[i]=s*f[n]+t[i]*f[i];
    		g[i]=(date){-f[i],t[i],dp[i]-s*f[i],i};
    	}
    	cdq(1,n);
    	printf("%lld",dp[n]);
    	return 0;
    }
    
  • 相关阅读:
    Bash快捷键
    Java Web学习笔记--JSP for循环
    Python学习笔记--简介
    Java学习笔记-数组
    JavaScript学习笔记一
    Java数组
    MongoDB学习---安装配置
    Java Web学习笔记-Servlet不是线程安全的
    Java Web学习笔记-重定向Redirect
    获取汇率的BAPI
  • 原文地址:https://www.cnblogs.com/cjk2001/p/6530502.html
Copyright © 2020-2023  润新知