码迷,mamicode.com
首页 > 其他好文 > 详细

[SDOI2012]任务安排 - 斜率优化dp

时间:2020-01-30 17:40:02      阅读:92      评论:0      收藏:0      [点我收藏+]

标签:def   include   set   提前   ++   ons   c++   复杂   思想   

虽然以前学过斜率优化dp但是忘得和没学过一样了。就当是重新学了。

题意很简单(反人类),利用费用提前的思想,考虑这一次决策对当前以及对未来的贡献,设 \(f_i\) 为做完前 \(i\) 个任务的贡献,\(t_i\) 为时间前缀和, \(c_i\) 为费用前缀和,容易得到

\[f_i = Min_{0 \leq j < i} (f_j + t_i (c_i - c_j) + s (c_n - c_j)\]

直接暴力转移,时间复杂度 \(O(n^2)\)

考虑斜率优化,将转移关系变形为

\[f_j = (s+t_i) c_j + f_i - t_i c_i - s c_n\]

\(y=f_j, x=c_j\) ,则转化为标准线性形式 \(y=Ax+B\)

我们要最小化 \(f_i\) 就要最小化 \(B\)

如果原题中每个任务的完成时间都为正数,那么转移时 \(A\) 是单调增的,可以用单调队列维护。

这里任务的完成时间可以为负(很反人类嘛),在单调栈上二分即可。

细节手推公式 + 小心写代码。

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 300005;

int n,s,t[N],c[N],f[N],l,r,q[N];

int binsearch(int l,int r,int i) {
    while(l<r) {
        int mid = (l+r)/2;
        if((f[q[mid+1]]-f[q[mid]]) <= (s+t[i]) * (c[q[mid+1]]-c[q[mid]]))
            l = mid+1;
        else
            r = mid;
    }
    return l;
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>s;
    for(int i=1;i<=n;i++) cin>>t[i]>>c[i];
    for(int i=1;i<=n;i++) t[i]+=t[i-1];
    for(int i=1;i<=n;i++) c[i]+=c[i-1];
    l=1; r=1;
    memset(f, 0x3f, sizeof f);
    f[0]=0;
    for(int i=1;i<=n;i++) {
        int j = binsearch(l,r,i);
        f[i] = f[q[j]] + t[i]*(c[i]-c[q[j]]) + s*(c[n]-c[q[j]]);
        while(l<r && (f[q[r]]-f[i])*(c[q[r]]-c[q[r-1]]) >= (c[q[r]]-c[i])*(f[q[r]]-f[q[r-1]])) r--;
        q[++r] = i;
    }
    cout<<f[n]<<endl;
}

[SDOI2012]任务安排 - 斜率优化dp

标签:def   include   set   提前   ++   ons   c++   复杂   思想   

原文地址:https://www.cnblogs.com/mollnn/p/12243060.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!