Slope optimization

Problem: task scheduling

There are N tasks in a sequence waiting to be executed on a machine, and the sequence must not be changed. To divide N tasks into several batches, each batch is of course several consecutive tasks. Starting from time 0 (only one machine, single thread), the time required to execute the i-th task is T[i]. Before each batch starts, the machine takes S time to power on. And the tasks in a batch are to be finished together after the batch has been processed. It is easy to get, if j belongs to the xth batch of tasks (k is the last of this batch of tasks), then the time he has to wait is S*j + sum(1 ~ k). Each task has a cost coefficient C[i], and the cost is the waiting time*C[i]. Please plan a batch plan to minimize costs.

For the convenience of expression, we define sumT and sumC as the prefix sum of T and C.

Task 1(tyvj1098)

Data range: 1 ≤ N ≤ 5000, 1 ≤ S ≤ 50, 1 ≤ T[i], C[i] ≤ 100.

Solution one:

        F[i][j] represents the minimum cost of dividing the first i tasks into j batches, then there is a transfer equation:

                                F[i][j] = min{F[k][j - 1] + (S * j + sumT[i]) * (sumC[i] - sumC[k])} k∈[0, i)   复杂度O(n³)。

        Obviously not getting full marks.

Solution two:

        In solution 1, we used a parameter to represent the number of batches, which is to provide a coefficient for multiplying S. In fact, every time we create a new batch of tasks, we can double S for the subsequent accumulation, eliminating this dimension and optimizing the complexity to O(n²).

                                F[i] = min{F[j] + sumT[i] * (sumC[i] - sumC[j]) + S * (sumC[N] - sumC[j])}   j∈[0, i)

        This is a classic idea called "fee advance calculation".

long long f[5010], sumt[5010], sumc[5010];
int n, s;
int main() {
	scanf("%d%d", &n, &s);
	for(int i = 1; i <= n; ++i) {
		int t, c;
		scanf("%d%d", &t, &c);
		sumt [i] = sumt [i - 1] + t;
		sumc[i] = sumc[i - 1] + c;
	}
	memset(f, 0x3f, sizeof(f));
	for(int i = 1; i <= n; ++i)
		for(int j = 0; j < i; ++j)
			f[i] = min(f[i], f[j] + sumt[i] * (sumc[i] - sumc[j]) + s * (sumc[n] - sumc[j]));
	printf("%lld", f[n]);
	return 0;
}

Task 2(IOI2002/POJ1180)

Data range: 1 ≤ N ≤ 3e5, 1 ≤ S, T[i], C[i] ≤ 512.

Due to the sharp increase in the range of N, we need to optimize the transition equation of solution 2 above. Consider the quantity with j as the independent variable.

 F[i] = min{F[j] - (sumT[i] + S) * sumC[j] + sumT[i] * sumC[i] + S * sumC[N]}   j∈[0, i)

Then we study the formula within min. Since F[i] must be obtained by some j, we might as well remove min. directly make:

F[i] = F[j] - (sumT[i] + S) * sumC[j] + sumT[i] * sumC[i] + S * sumC[N]。

Then move the item: (with F[j] as the ordinate and sumC[j] as the abscissa)

F[j] = (sumT[i] + S) * sumC[j] + F[i] - sumT[i] * sumC[i] - S * sumC[N]。

This is a line with sumT[i] + S as the slope and F[i] - sumT[i] * sumC[i] - S * sumC[N] as the intercept.

So our optimal sub-option is a set of points in a coordinate system.

Except for F[i], the slope and intercept are fixed values. To make F[i] as small as possible, it is to make the intercept as small as possible.

Since the slope is fixed, we use a straight line with a fixed slope to translate from bottom to top, and the first one encountered is the optimal solution (the intercept is the smallest at this time).

For any three decision points (sumC[j1], F[j1]), (sumC[j2], F[j2]), (sumC[j3], F[j3]), let j1 < j2 < j3, Because T and C are both positive integers (this is very important), there is also sumC[j1] < sumC[j2] < sumC[j3].

Then, if j1, j2, and j3 form an upward convex shape, j2 must not be the optimal decision. If it constitutes a downward convexity, it may be the optimal decision.

Therefore, the necessary conditions for j2 to become the optimal decision are:

(F[j2] - F[j1])/(sumC[j2] - sumC[j1]) < (F[j3] - F[j2])/(sumC[j3] - sumC[j2]) (ie, a convex hull)

In layman's terms, we should maintain a lower convex hull that "connects two adjacent points to obtain a monotonically increasing line segment slope".

For an i, we denote k[i] as sumT[i] + S, then the optimal solution should take the smallest j, and j satisfies k(j, j + 1) > k[i] (you can know by drawing Now, if k[i] is bigger, then it can directly reach the later point).

#include <cstdio>
#define N 300010
typedef long long ll;
int n, q[N]; ll s, sumt[N], sumc[N], f[N];
inline int read() {
	int x = 0; char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = getchar();}
	return x;
}
int main() {
	n = read(); s = read();
	for(int i = 1; i <= n; ++i) {
		int t = read(), c = read();
		sumt[i] = sumt[i - 1] + t; sumc[i] = sumc[i - 1] + c;
	}
	f[0] = 0; int l = 1, r = 1; q[1] = 0;
	for(int i = 1; i <= n; ++i) {
		while(l < r && (f[q[l + 1]] - f[q[l]]) <= (s + sumt[i]) * (sumc[q[l + 1]] - sumc[q[l]])) ++l;
		f[i] = f[q[l]] - (s + sumt[i]) * sumc[q[l]] + sumt[i] * sumc[i] + s * sumc[n];
		while(l < r && (f[q[r]] - f[q[r - 1]]) * (sumc[i] - sumc[q[r]]) >= (f[i] - f[q[r]]) * (sumc[q[r]] - sumc[q[r - 1]])) --r;
		q[++r] = i;
	}
	printf("%lld", f[n]);
	return 0;
}

Task 3(BZOJ2726)

Data range: 1 ≤ N ≤ 3e5, 0 ≤ S, C[i] ≤ 512, -512 ≤ T[i] ≤ 512.

T[i] can be negative, which means that sumT is no longer monotonic, and thus, the slope S+sumT[i] is no longer monotonic. We can't ++l (deleting the head of the line is because of the monotonicity of the slope, we can't use it now, and we won't use it in the future). So maintain the entire convex hull (the decision slope should increase monotonically).

Then, the head of the queue is not necessarily the best decision, so we divide the queue into two and find a position p such that k(p - 1, p) ≤ k[i] ≤ k(p, p + 1), p is optimal decision.

#include <cstdio>
#define N 300010
typedef long long ll;
int n, q[N], l, r; ll s, sumt[N], sumc[N], f[N];
inline int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
	while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = getchar();}
	return x * f;
}
inline int binary_search(int k) {
	if(l == r) return q[l];
	int L = l, R = r;
	while(L < R) {
		int mid = (L + R)>>1;
		if(f[q[mid + 1]] - f[q[mid]] <= k * (sumc[q[mid + 1]] - sumc[q[mid]])) L = mid + 1;
		else R = mid;
	}
	return q[L];
}
int main() {
	n = read(); s = read();
	for(int i = 1; i <= n; ++i) {
		int t = read(), c = read();
		sumt[i] = sumt[i - 1] + t; sumc[i] = sumc[i - 1] + c;
	}
	f[0] = 0; l = 1, r = 1; q[1] = 0;
	for(int i = 1; i <= n; ++i) {
//		while(l < r && (f[q[l + 1]] - f[q[l]]) <= (s + sumt[i]) * (sumc[q[l + 1]] - sumc[q[l]])) ++l;
		int p = binary_search(s + sumt[i]);
		f[i] = f[p] - (s + sumt[i]) * sumc[p] + sumt[i] * sumc[i] + s * sumc[n];
		while(l < r && (f[q[r]] - f[q[r - 1]]) * (sumc[i] - sumc[q[r]]) >= (f[i] - f[q[r]]) * (sumc[q[r]] - sumc[q[r - 1]])) --r;
		q[++r] = i;
	}
	printf("%lld", f[n]);
	return 0;
}

Task 4

If T is positive, C may be negative, how to deal with it?


Task 5

What if both T and C may be negative?

Obviously, the dynamic interpolation of the balanced tree is enough, and the entire convex hull is still maintained, and the binary search is performed.


T4 solution and T4, T5 codes will be added tomorrow.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325836919&siteId=291194637