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, 就是给一些点和一个斜率...然后最小化截距, 显然维护下凸包就可以了. 然后因为无比坑爹的出题人....时间可以为负数, 所以要用平衡树维护(假如时间为非负数用单调队列就行了)....或者cdq分治. O(N log N)平衡树维护大家都应该会...cdq分治就是对于[l, r), m=(l+r)/2, 处理[m, r)的dp值对[l, m)dp值的贡献(这道题是从后往前dp). 具体就是暴力建[m, r)的凸包, 然后[l, m)的按斜率排序, 依次询问. 预处理一下, 时间复杂度就是O(N log N)了, 空间复杂度是O(N).

-------------------------------------------------------------------------------------------------

#include<cstdio>

#include<cstring>

#include<iostream>

#include<algorithm>

using namespace std;

typedef long long ll;

const int maxn = 300009;

int N, S, V[maxn], q[maxn], stk[maxn], T[maxn], F[maxn];

ll dp[maxn];

void Init() {

scanf("%d%d", &N, &S);

for(int i = 0; i < N; i++) {

scanf("%d%d", T + i, F + i);

q[i] = N - i - 1;

}

T[N] = F[N] = 0;

for(int i = N; i--; )

T[i] += T[i + 1], F[i] += F[i + 1];

}

bool chk(int a, int b, int c) {

int xl = T[b] - T[a], xr = T[c] - T[b];

ll yl = dp[b] - dp[a], yr = dp[c] - dp[b];

return ((xl < 0) ^ (xr < 0)) ? yl * xr <= yr * xl : yl * xr >= yr * xl;

}

bool Jud(int a, int b, int k) {

ll x = T[b] - T[a], y = dp[b] - dp[a];

return x < 0 ? y > x * k : y < x * k;

}

ll calc(int x, int y) {

return dp[y] + ll(F[x]) * (T[x] - T[y] + S);

}

// [l, r)

void cdq(int l, int r) {

if(l + 1 == r) return;

int m = (l + r) >> 1;

int ql = l, qr = m;

for(int i = l; i < r; i++)

q[i] < m ? V[ql++] = q[i] : V[qr++] = q[i];

for(int i = l; i < r; i++) q[i] = V[i];

cdq(m, r);

int h = 0, t = -1;

for(int i = m; i < r; i++) {

while(t > 0 && chk(stk[t - 1], stk[t], q[i])) t--;

stk[++t] = q[i];

}

for(int i = l; i < m; i++) {

while(h < t && Jud(stk[h], stk[h + 1], F[q[i]])) h++;

dp[q[i]] = min(dp[q[i]], calc(q[i], stk[h]));

}

cdq(l, m);

ql = l, qr = m;

for(int i = l; i < r; i++) if(ql >= m) {

V[i] = q[qr++];

} else if(qr >= r) {

V[i] = q[ql++];

} else

V[i] = T[q[ql]] < T[q[qr]] ? q[ql++] : q[qr++];

for(int i = l; i < r; i++) q[i] = V[i];

}

void Work() {

for(int i = 0; i < N; i++)

dp[i] = ll(F[i]) * (T[i] + S);

cdq(0, N);

printf("%lld\n", dp[0]);

}

int main() {

Init();

Work();

return 0;

}

-------------------------------------------------------------------------------------------------

2726: [SDOI2012]任务安排

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 660  Solved: 171
[Submit][Status][Discuss]

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

HINT

Source

时间: 2024-10-18 21:03:25

BZOJ 2726: [SDOI2012]任务安排( dp + cdq分治 )的相关文章

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[

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分治)

[题目链接] 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 2244: [SDOI2011]拦截导弹 DP+CDQ分治

2244: [SDOI2011]拦截导弹 Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小.也就是拦截导弹的数量最多的方案.但是

bzoj 2726: [SDOI2012]任务安排

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

BZOJ 1492 NOI 2007 货币兑换Cash CDQ分治+斜率优化DP

题目大意:有两种金券,A和B.每一天有一个rate值,表示购入的比例:还有每一天AB金券的售价.现在给出初始的钱数,问最后能够获得多少钱. 思路:这算是神题了吧,啃论文啃别人代码将近一天才算有点明白. 首先题目中说的可以买一部分或者卖一部分是扯淡的,因为为了最大获利一定要全部买入,全部卖出.朴素的DP方程就好弄了. 设f[i]为第i天最多的B券的数量.那么f[i] = (rate[j] * f[j] * a[i] + f[j] * b[i]) / (rate[i] * a[i] + b[i])

[BZOJ 1492][NOI2007]货币兑换Cash(CDQ分治+斜率优化Dp)

Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的 价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法 .比例交易法分为两个方面:(a)卖出金券:顾客提

HDU5322 Hope(DP + CDQ分治 + NTT)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5322 Description Hope is a good thing, which can help you conquer obstacles in your life, just keep fighting, and solve the problem below. In mathematics, the notion of permutation relates to the ac

bzoj1492--斜率优化DP+cdq分治

显然在某一天要么花完所有钱,要么不花钱. 所以首先想到O(n^2)DP: f[i]=max{f[i-1],(f[j]*r[j]*a[i]+f[j]*b[i])/(a[j]*r[j]+b[j])},j<i 其中f[j]*r[j]/(a[j]*r[j]+b[j])是第j天最多能买多少A券,B类似. 假如我们已经找到了最优的j,那么有f[i]=(f[j]*r[j]*a[i]+f[j]*b[i])/(a[j]*r[j]+b[j]) 令x[j]=f[j]*r[j]/(a[j]*r[j]+b[j]),y[j