zoukankan      html  css  js  c++  java
  • 【BZOJ2726】[SDOI2012]任务安排 斜率优化+cdq分治

    【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

    题解:用f[i]表示做完前i个任务的最小费用,但是做完当前任务的时间对后面的任务也会造成影响,所以我们提前应计算费用,不难列出方程:

    设st表示T的前缀和,sf表示F的前缀和,所以有:

    $f[i]=min { f[j]+(st[i]-st[j]+S)*(sf[n]-sf[j])}$

    移个项显然就变成了斜率优化的形式。不过坑的地方是,T可能是负数,所以斜率不是单调的,所以用cdq分治即可。

     

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=300010;
    typedef long long ll;
    typedef long double ld;
    int n;
    ll S;
    struct node
    {
    	int x,org,k;
    	ll y,f;
    }s[maxn],p[maxn];
    int q[maxn];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    bool cmpk(const node &a,const node &b)
    {
    	return a.k>b.k;
    }
    bool cmpo(const node &a,const node &b)
    {
    	return a.org<b.org;
    }
    inline ld slope(int a,int b)
    {
    	if(s[a].x==s[b].x)	return (s[b].y>=s[a].y)?(1e20):(-1e20);
    	else	return ld(s[b].y-s[a].y)/(s[b].x-s[a].x);
    }
    void solve(int l,int r)
    {
    	if(l==r)
    	{
    		s[l].y=(ll)s[l].x*(s[l].k-S)-s[l].f;
    		return ;
    	}
    	register int mid=(l+r)>>1,i,h1=l,h2=mid+1;
    	for(i=l;i<=r;i++)
    	{
    		if(s[i].org<=mid)	p[h1++]=s[i];
    		else	p[h2++]=s[i];
    	}
    	for(i=l;i<=r;i++)	s[i]=p[i];
    	solve(l,mid);
    	register int h=1,t=0;
    	for(i=l;i<=mid;i++)
    	{
    		while(h<t&&slope(q[t],i)>=slope(q[t-1],q[t]))	t--;
    		q[++t]=i;
    	}
    	for(i=mid+1;i<=r;i++)
    	{
    		while(h<t&&slope(q[h],q[h+1])>=s[i].k)	h++;
    		s[i].f=min(s[i].f,s[q[h]].f+s[q[h]].x*(s[i].k-s[q[h]].k+S));
    	}
    	solve(mid+1,r);
    	h1=l,h2=mid+1;
    	for(i=l;i<=r;i++)
    	{
    		if(h1<=mid&&(h2>r||s[h1].x<s[h2].x))	p[i]=s[h1++];
    		else	p[i]=s[h2++];
    	}
    	for(i=l;i<=r;i++)	s[i]=p[i];
    }
    int main()
    {
    	n=rd(),S=rd();
    	int i;
    	for(i=1;i<=n;i++)	s[i].k=s[i-1].k+rd(),s[i-1].x=rd(),s[i].org=i;
    	for(i=n-1;i>=0;i--)	s[i].x+=s[i+1].x;
    	for(i=1;i<=n;i++)	s[i].f=s[0].x*(s[i].k+S);
    	sort(s+1,s+n+1,cmpk);
    	solve(1,n);
    	sort(s+1,s+n+1,cmpo);
    	printf("%lld",s[n].f);
    	return 0;
    }

     

  • 相关阅读:
    总结一下最近用过的phpcms语法
    phpcms和php格式化时间戳
    为什么使用bootstrap在一个页面同时做两个轮播效果时,只有第一个有效??
    Jquery右击显示菜单事件,运用smartMenu插件。
    流程管理
    权限管理
    文件管理的练习(目录文件的打开,双击返回上一层目录、双击打开子目录文件)
    php部分--文件操作
    php部分--头像上传预览
    PHP部分--图片上传服务器、图片路径存入数据库,并读取
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7859042.html
Copyright © 2011-2022 走看看