bzoj 2726: [SDOI2012]任务安排【cdq+斜率优化】

cdq复健.jpg

首先列个n方递推,设sf是f的前缀和,st是t的前缀和:

\[
f[i]=min(f[j]+s*(sf[n]-sf[j])+st[i]*(sf[i]-sf[j]))
\]

然后移项:

\[
f[i]=f[j]+s*sf[n]-s*sf[j]+st[i]*sf[i]-st[i]*sf[j]
\]

\[
f[i]=f[j]+s*sf[n]+st[i]*sf[i]-s*sf[j]-st[i]*sf[j]
\]

\[
f[i]=f[j]+s*sf[n]+st[i]*sf[i]-sf[j]*(s+st[i])
\]

\[
f[i]+sf[j]*(s+st[i])=f[j]+s*sf[n]+st[i]*sf[i]
\]

然后看成斜率表达式b+kx=y,那么

\[
b=f[i],x=sf[j],k=(s+st[i]),y=f[j]+s*sf[n]+st[i]*sf[i]
\]

然后因为有负数所以这并不能用单调队列,splay是很方便但是又太长了

选择cdq

和bzoj 1492差不多,只是上凸壳变成下凸壳了,详见https://www.cnblogs.com/lokiii/p/9199587.html

注意!!转移的时候不是f[i]而是f[a[i].id]!!!我简直zz……

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const long long N=500005,inf=1e18;
long long n,s[N],m,dz,f[N];
struct dian
{
    double x,y;
    bool operator < (const dian &b) const
    {
        return (x<=b.x)||(x==b.x&&y<=b.y);
    }
}p[N],q[N];
struct qwe
{
    long long st,sf,k,id;
}a[N],b[N];
bool cmp(const qwe &a,const qwe &b)
{
    return a.k<b.k;
}
long long read()
{
    long long r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
double wk(long long i,long long j)
{
    return (p[i].y-p[j].y)/(p[i].x-p[j].x);
}
void cdq(long long l,long long r)
{
    if(l==r)
    {
        f[l]=min(f[l],(long long)(dz+a[l].st*a[l].sf));
        p[l].x=a[l].sf;
        p[l].y=f[l];
        return;
    }
    long long mid=(l+r)>>1,top=0,l1=l,l2=mid+1;
    for(long long i=l;i<=r;i++)
    {
        if(a[i].id<=mid)
            b[l1++]=a[i];
        else
            b[l2++]=a[i];
    }
    for(long long i=l;i<=r;i++)
        a[i]=b[i];
    cdq(l,mid);
    for(long long i=l;i<=mid;i++)
    {
        while(top>1&&wk(i,s[top])<wk(s[top],s[top-1]))
            top--;
        s[++top]=i;
    }//cerr<<top<<endl;
    for(long long i=mid+1,j=1;i<=r;i++)
    {
        while(j<top&&wk(s[j+1],s[j])<(double)a[i].k)
            j++;//cerr<<i<<"   "<<s[j]<<endl;
        f[a[i].id]=min(f[a[i].id],(long long)(p[s[j]].y+dz+a[i].st*a[i].sf-p[s[j]].x*(m+a[i].st)));
    }
    cdq(mid+1,r);
    l1=l,l2=mid+1;
    for(long long i=l;i<=r;i++)
    {
        if((p[l1]<p[l2]||l2>r)&&l1<=mid)
            q[i]=p[l1++];
        else
            q[i]=p[l2++];
    }
    for(long long i=l;i<=r;i++)
        p[i]=q[i];
}
int main()
{
    n=read(),m=read();
    for(long long i=1;i<=n;i++)
        a[i].st=a[i-1].st+read(),a[i].sf=a[i-1].sf+read(),a[i].k=m+a[i].st,a[i].id=i;
    dz=m*a[n].sf;//cerr<<dz<<"!"<<endl;
    sort(a+1,a+1+n,cmp);
    for(long long i=1;i<=n;i++)
        f[i]=inf;
    cdq(1,n);
    // for(int i=1;i<=n;i++)
        // cerr<<f[i]<<endl;
    printf("%lld\n",f[n]);
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/9241250.html

时间: 2024-10-02 19:41:27

bzoj 2726: [SDOI2012]任务安排【cdq+斜率优化】的相关文章

poj 2726: [SDOI2012]任务安排【斜率优化dp】

我会斜率优化了!这篇讲的超级棒https://blog.csdn.net/shiyongyang/article/details/78299894?readlog 首先列个n方递推,设sf是f的前缀和,st是t的前缀和:\( f[i]=min(f[j]+s(sf[n]-sf[j])+st[i](sf[i]-sf[j])) \) 然后移项: \[ f[i]=f[j]+s*sf[n]-s*sf[j]+st[i]*sf[i]-st[i]*sf[j] \] \[ f[i]=f[j]+s*sf[n]+st

bzoj 2726 [SDOI2012]任务安排(斜率DP+CDQ分治)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2726 [题意] 将n个任务划分成若干个块,每一组Mi任务花费代价(T+sigma{ tj }+s)*sima{ fi },j属于Mi,T为当前时间,问最小代价. [思路] 设f[i]为将前i个任务划分完成的最小费用,Ti Fi分别表示t和f的前缀和,则不难写出转移方程式: f[i]=min{ f[j]+(F[n]-F[j])*(T[i]-T[j]+s) },1<=j<=i-1 经过

BZOJ 2726: [SDOI2012]任务安排 [斜率优化DP 二分 提前计算代价]

2726: [SDOI2012]任务安排 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 868  Solved: 236[Submit][Status][Discuss] Description 机器上有N个需要处理的任务,它们构成了一个序列.这些任务被标号为1到N,因此序列的排列为1,2,3...N.这N个任务被分成若干批,每批包含相邻的若干任务.从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti.在每批任务开始前,机器需要启

BZOJ 2726: [SDOI2012]任务安排( dp + cdq分治 )

考虑每批任务对后面任务都有贡献, dp(i) = min( dp(j) + F(i) * (T(i) - T(j) + S) ) (i < j <= N)  F, T均为后缀和. 与j有关的量只有t = dp(j) - F(i) * T(j) , 我们要最小化它. dp(j)->y, T(j)->x, 那么y = F(i) * x + t, 就是给一些点和一个斜率...然后最小化截距, 显然维护下凸包就可以了. 然后因为无比坑爹的出题人....时间可以为负数, 所以要用平衡树维护(

BZOJ2726 [SDOI2012]任务安排 【斜率优化 + cdq分治】

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

bzoj 2726: [SDOI2012]任务安排

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

【BZOJ 1492】 [NOI2007]货币兑换Cash 斜率优化DP

先说一下斜率优化:这是一种经典的dp优化,是OI中利用数形结合的思想解决问题的典范,通常用于优化dp,有时候其他的一些决策优化也会用到,看待他的角度一般有两种,但均将决策看为二维坐标系上的点,并转化为维护凸壳,一种根据两点的斜率与某一常数的大小关系推断二者的优劣,一种将转移方程化为相关直线方程,通过取得最大(小)截距来求最优解.关于其实现方法上,当点的x坐标单调时,可依据比较常数是否单调选择单调队列或单调栈,而当其x坐标不单调时常常使用CDQ分治或平衡树来实现. 千万别用替罪羊来写动态凸壳!!!

BZOJ 1096: [ZJOI2007]仓库建设( dp + 斜率优化 )

dp(v) = min(dp(p)+cost(p,v))+C(v) 设sum(v) = ∑pi(1≤i≤v), cnt(v) = ∑pi*xi(1≤i≤v), 则cost(p,v) = x(v)*(sum(v)-sum(p)) - (cnt(v)-cnt(p)) 假设dp(v)由dp(i)转移比dp(j)转移优(i>j), 那么  dp(i)+cost(i,v) < dp(j)+cost(j,v) 即 dp(i)+x(v)*(sum(v)-sum(i))-(cnt(v)-cnt(i)) <

BZOJ 1096 [ZJOI2007]仓库建设(斜率优化DP)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1096 [题目大意] 有个斜坡,有n个仓库,每个仓库里面都有一些物品,物品数目为p,仓库位置为x,修缮仓库需要的费用为c,现在下雨了,之后修缮的仓库才能放东西,别的地方的仓库要运东西过来,但是只能往比它地势低的运,问所有物品得到保障的最小代价. [题解] 显然可以从高处往低处做DP,dp[i]=min(dp[j]+cost(i,j)) 我们记s[i]为p[i]的前缀和,b[i]为x[i