bzoj2726: [SDOI2012]任务安排
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
分析
方程写出来
拆开
设
化成斜截式可以搞斜率优化Dp
但是出题人的脑洞是时间可以是负数。
于是只好套一个分治。
具体见bzoj1492
里面有方法。
分析
#include<cstdio>
#include<algorithm>
const int N = 5e5 + 10; const double eps = 1e-10;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + c - '0'; return x * f;
}
int h[N], n, S; long long f[N], G;
struct data {
long long k, x, y; int i;
void In(int id) {k = ri(); x = ri(); i = id;}
void Get() {y = ::f[i] + 1LL * (x - G) * k - x * S;}
void Tra(data j) {f[i] = std::min(f[i], j.y - j.x * k + G * (S + k));}
bool operator < (data b) {return x == b.x ? y < b.y : x < b.x;}
}p[N], q[N];
bool cmp(data a, data b) {return a.k < b.k;}
long long U(int j, int k) {return q[k].y - q[j].y;}
long long D(int j, int k) {return q[k].x - q[j].x;}
void Solve(int L, int R) {
if(L == R) return p[L].Get();
int m = L + R >> 1; int s = L, t = m + 1;
for(int i = L; i <= R; ++i) p[i].i <= m ? q[s++] = p[i] : q[t++] = p[i];
for(int i = L; i <= R; ++i) p[i] = q[i];
Solve(L, m); int tp = 0;
for(int i = L;i <= m; ++i) {
for(;tp > 1 && U(h[tp - 1], h[tp]) * D(h[tp], i) > D(h[tp - 1], h[tp]) * U(h[tp], i); ) --tp;
h[++tp] = i;
} int j = 1;
for(int i = m + 1; i <= R; ++i) {
for(;j < tp && U(h[j], h[j + 1]) < p[i].k * D(h[j], h[j + 1]);) ++j;
p[i].Tra(p[h[j]]);
}
Solve(m + 1, R); s = L; t = m + 1; tp = L;
for(;s <= m && t <= R;) q[tp++] = (p[s] < p[t] ? p[s++] : p[t++]);
for(;s <= m;) q[tp++] = p[s++]; for(;t <= R;) q[tp++] = p[t++];
for(int i = L;i <= R; ++i) p[i] = q[i];
}
int main() {
n = ri(); S = ri();
for(int i = 1;i <= n; ++i) p[i].In(i), f[i] = 1e18;
for(int i = 2;i <= n; ++i) p[i].x += p[i - 1].x, p[i].k += p[i - 1].k;
G = p[n].x; std::sort(p + 1, p + n + 1, cmp);
Solve(0, n); printf("%lld\n", f[n]);
return 0;
}