Given a sequence with a length of n and a constant m, we can divide the sequence into random segments. The weight of each segment is sum (arr [I]). + C (x <= I <= y), evaluate a division method to minimize the weight of the entire sequence. n <= 0.5 million.
Solution: After finishing the Hdu 2829, let's look at this question again. Everything becomes so simple and can be solved in two ways.
The state transition equation is dp [I] = min (dp [j] + (sum [I]-sum [j]) ^ 2 + m) (j <I );
Method 1: dp [I] = dp [j] + (sum [I]-sum [j]) ^ 2 + m = dp [j] + sum [I] * sum [I] + sum [j] * sum [j]-2 * sum [I] * sum [j] + m;
Set y = dp [j] + sum [j] * sum [j], x = sum [j], then the original formula is equal: dp [I] = y + 2 * sum [I] * x + m + sum [I] * sum [I], and then set the bottom slope optimization DP template to ac.
Method 2: The Optimization Technique Used in method 2 is similar to a quadrilateral inequality. A s [I] is used to record the dp [I] from which the preceding State is transferred, then, just enumerate s [I-1] To I-1.
The second method seems to be slower than the first one, and the constant is relatively large.
Test data:
Input
5 5
5 9 5 7 5
1 1000
1
3 1000
1 3 5
3 0
1 3 5
1 0
100000
OutPut:
230
1001
1081
35
10000000000
C producer code:
[Cpp]
# Include <stdio. h>
# Include <string. h>
# Deprecision MAX 510000
# Define int64 long
Struct point {
Int64 x, y, c;
} Pot [MAX];
Int n, m, arr [MAX];
Int64 sum [MAX], dp [MAX];
Int qu [MAX], head, tail;
Int CheckIt (int x, int y, int z ){
Point p0 = pot [x], p1 = pot [y], p2 = pot [z];
Return (p0.x-p1.x) * (p0.y-p2.y)-(p0.y-p1.y) * (p0.x-p2.x) <= 0;
}
Int NotBest (int x, int y, int k ){
Point p0 = pot [x], p1 = pot [y];
Return p0.y-k * p0.x> p1.y-k * p1.x;
}
Int64 Solve_DP (){
Head = tail = 0;
Qu [tail] = 0;
Pot [0]. x = pot [0]. y = 0;
For (int I = 1; I <= n; ++ I ){
Pot [I]. x = sum [I-1];
Pot [I]. y = dp [I-1] + sum [I-1] * sum [I-1];
While (head <= tail-1 &&
CheckIt (qu [tail-1], qu [tail], I) tail --;
Qu [++ tail] = I;
While (head + 1 <= tail &&
NotBest (qu [head], qu [head + 1], 2 * sum [I]) head ++;
Int k = qu [head];
Dp [I] = pot [k]. y-2 * sum [I] * pot [k]. x + sum [I] * sum [I] + m;
}
Return dp [n];
}
Int64 Solve_DP2 (){
For (int64 mmin, I = 1; I <= n; ++ I ){
Mmin =-1;
For (int j = qu [I-1]; j <I; ++ j)
If (mmin =-1 |
Dp [j] + (sum [I]-sum [j]) * (sum [I]-sum [j]) <mmin ){
Mmin = dp [j] + (sum [I]-sum [j]) * (sum [I]-sum [j]);
Qu [I] = j;
}
Dp [I] = mmin + m;
}
Return dp [n];
}
Int main ()
{
Int I, j, k; www.2cto.com
While (scanf ("% d", & n, & m )! = EOF ){
For (I = 1; I <= n; ++ I)
Scanf ("% d", & arr [I]), sum [I] = arr [I] + sum [I-1];
Int64 ans = Solve_DP2 ();
Printf ("% lld \ n", ans );
}
}