[SDOI2012]任务安排 - 斜率优化dp
Posted mollnn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2012]任务安排 - 斜率优化dp相关的知识,希望对你有一定的参考价值。
虽然以前学过斜率优化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的主要内容,如果未能解决你的问题,请参考以下文章
poj 2726: [SDOI2012]任务安排斜率优化dp
bzoj 2726 [SDOI2012]任务安排(斜率DP+CDQ分治)
luogu P5785 [SDOI2012]任务安排 斜率dp+二分
BZOJ2726[SDOI2012]任务安排 斜率优化+cdq分治