任务安排「SDOI2012」

Posted Ilverene

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了任务安排「SDOI2012」相关的知识,希望对你有一定的参考价值。

题意

有一个数列,每个元素均有一个完成耗时\(t_i\)与完成耗费\(f_i\),每个元素的耗费等于其完成时刻乘以完成耗费。可以将这些元素分为任意组,每一组的元素完成时刻一样。每一组都会有一个固定的额外时间耗费\(s\)。数据范围\(3*10^5\)


思路

首先推出状态转移方程\(dp[i]=min(dp[j]+s*(sumf[n]-sumf[j])+sumt[i]*(sumf[i]-sumf[j]))\)

拆开可以得到斜率

\(\frac{dp[j]-dp[k]}{sumf[j]-sumf[k]}>s+sumt[i]\)

然而斜率不具有单调性,因此考虑\(CDQ\)分治。

左侧直接更新右侧即可。


代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {

    template<typename T>inline void read (T &x) {
        x=0;T f=1;char c=getchar();
        for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
        for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
        x*=f;
    }

    template<typename T>inline void write (T x) {
        if (x<0) putchar('-'),x*=-1;
        if (x>=10) write(x/10);
        putchar(x%10+'0');
    }

}

using namespace StandardIO;

namespace Project {
    #define int long long
    
    const int N=300300;
//  const int INF=2147483647;
    
    int n,s,head,tail;
    int t[N],f[N],dp[N];
    struct node {
        int id;
        int x,y;
        node () {}
        node (int _x,int _y) : x(_x),y(_y) {}
        friend node operator + (const node &x,const node &y) {
            return node(x.x+y.x,x.y+y.y);
        }
        friend node operator - (const node &x,const node &y) {
            return node(x.x-y.x,x.y-y.y);
        }
        friend int operator * (const node &x,const node &y) {
            return x.x*y.y-x.y*y.x;
        }
    } w[N],queue[N],tmp[N];
    
    inline bool cmpid (const node &x,const node &y) {
        return t[x.id]<t[y.id];
    }
    inline bool cmpx (const node &x,const node &y) {
        return (x.x==y.x)?(x.y<y.y):(x.x<y.x);
    }
    inline double slope (node x,node y) {
        return static_cast<double>(x.y-y.y)/static_cast<double>(x.x-y.x);
    }
    void merge1 (int l,int r) {
        int mid=(l+r)>>1,ptr_l=l,ptr_r=mid+1;
        for (register int i=l; i<=r; ++i) {
            if (w[i].id<=mid) tmp[ptr_l++]=w[i];
            else tmp[ptr_r++]=w[i];
        }
        for (register int i=l; i<=r; ++i) w[i]=tmp[i];
    }
    void merge2 (int l,int r) {
        int mid=(l+r)>>1,ptr_l=l,ptr_r=mid+1;
        for (register int i=l; i<=r; ++i) {
            if (ptr_l<=mid&&(ptr_r>r||cmpx(w[ptr_l],w[ptr_r]))) tmp[ptr_l++]=w[i];
            else tmp[ptr_r++]=w[i];
        }
        for (register int i=l; i<=r; ++i) w[i]=tmp[i];
    }
    void CDQ (int l,int r) {
        if (l==r) return w[l].x=f[w[l].id],w[l].y=dp[w[l].id],void();
        int mid=(l+r)>>1;merge1(l,r),CDQ(l,mid),head=1,tail=0;
        for (register int i=l; i<=mid; ++i) {
            while (head<tail&&(queue[tail]-queue[tail-1])*(w[i]-queue[tail-1])<0) --tail;
            queue[++tail]=w[i];
        }
        for (register int i=mid+1; i<=r; ++i) {
            while (head<tail&&slope(queue[head+1],queue[head])<s+t[w[i].id]) ++head;
            dp[w[i].id]=min(dp[w[i].id],dp[queue[head].id]+s*(f[n]-f[queue[head].id])+t[w[i].id]*(f[w[i].id]-f[queue[head].id]));
        }
        CDQ(mid+1,r),merge2(l,r);
    }

    inline void MAIN () {
        read(n),read(s);
        for (register int i=1; i<=n; ++i) read(t[i]),read(f[i]),t[i]+=t[i-1],f[i]+=f[i-1],w[i].id=i;
        sort(w+1,w+n+1,cmpid),memset(dp,0x3f,sizeof(dp)),dp[0]=0,CDQ(0,n);
        write(dp[n]);
    }
    
    #undef int
}

int main () {
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    Project::MAIN();
}

以上是关于任务安排「SDOI2012」的主要内容,如果未能解决你的问题,请参考以下文章

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

[SDOI2012]任务安排

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

bzoj 2726: [SDOI2012]任务安排

bzoj2726 [SDOI2012]任务安排

任务安排「SDOI2012」