C. Remove the Bracket
题意
给定一个长度为 n n n 的整数数组 a a a 和一个非负整数 s s s
- 要求 ∀ i ∈ [ 2 , n − 1 ] , 选定两个整数 x i , y i ,满足 x i + y i = s 且 ( x i − s ) ( y i − s ) ≥ 0 \forall i \in [2,n - 1],选定两个整数 x_i, y_i,满足 x_i + y_i = s 且 (x_i - s)(y_i - s) \geq 0 ∀i∈[2,n−1],选定两个整数xi,yi,满足xi+yi=s且(xi−s)(yi−s)≥0
定义花费: F = a 1 ⋅ x 1 + y 1 ⋅ x 2 + y 2 ⋅ x 3 + y 3 ⋅ x 4 + . . . + y n − 2 ⋅ x n − 1 + y n − 1 ⋅ a n F = a_1 \cdot x_1 + y_1 \cdot x_2 + y_2 \cdot x_3 + y_3 \cdot x_4 + ... + y_{n - 2} \cdot x_{n - 1} + y_{n -1 } \cdot a_n F=a1⋅x1+y1⋅x2+y2⋅x3+y3⋅x4+...+yn−2⋅xn−1+yn−1⋅an
求出满足限制的最小花费
思路
( x i − s ) ( y i − s ) ≥ 0 (x_i - s)(y_i - s) \geq 0 (xi−s)(yi−s)≥0 意味着: m i n ( x i , y i ) ≥ s min(x_i, y_i) \geq s min(xi,yi)≥s 或 m a x ( x i , y i ) ≤ s max(x_i, y_i) \leq s max(xi,yi)≤s,而 x i + y i = s x_i + y_i = s xi+yi=s
所以 x i x_i xi 的取值是一段连续的区间
如果我们记录位置 i i i 分裂出来的 y i y_i yi 对应的最小值,可能有 n × s n \times s n×s 种状态,考虑优化
我们注意到:对于当前的 i i i,如果我们分裂成了 x i x_i xi 和 y i y_i yi,那么它们会影响的位置只有:
y i − 1 ⋅ x i + y i ⋅ x i + 1 y_{i - 1} \cdot x_i + y_i \cdot x_{i + 1} yi−1⋅xi+yi⋅xi+1,我们假设 y i − 1 < x i + 1 y_{i -1} < x_{i + 1} yi−1<xi+1,当 x i x_i xi 加 1 1 1时, y i y_i yi 对应减 1 1 1,此时 F F F 的变化量为: δ = y i − 1 − x i + 1 < 0 \delta = y_{i - 1} - x_{i + 1} < 0 δ=yi−1−xi+1<0,总体 F F F 是在减小的!所以这种情况下我们要尽可能为 x i x_i xi 取到最大值
另外一种情况则 x i x_i xi 尽可能取到最小值; x i − 1 = y i + 1 x_{i -1} = y_{i + 1} xi−1=yi+1 时, x i x_i xi 取最大最小都无所谓
那么我们可以得出结论:每次 a i a_i ai 分裂都会往两种最值之一分裂,这就是典型的上下界 D P DP DP 求解最值问题
我们只需要在当前位置 i i i 记录两种取法的最小值即可, d p [ i ] [ 0 ] dp[i][0] dp[i][0] 表示这个位置取的是 x i x_i xi, y i y_i yi 留到后面; d p [ i ] [ 1 ] dp[i][1] dp[i][1] 则相反
时间复杂度: O ( 4 n ) O(4n) O(4n)
#include<bits/stdc++.h>
#define fore(i,l,r) for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
#define ALL(v) v.begin(), v.end()
#define Debug(x, ed) std::cerr << #x << " = " << x << ed;const int INF=0x3f3f3f3f;
const long long INFLL=1e18;typedef long long ll;int main(){std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);int t;std::cin >> t;while(t--){int n, s;std::cin >> n >> s;std::vector<ll> a(n + 1), x(n + 1), y(n + 1);std::vector<std::array<ll, 2>> dp(n + 1);fore(i, 1, n + 1){std::cin >> a[i];if(i == 1 || i == n) x[i] = y[i] = a[i];else if(s >= a[i]) x[i] = 0, y[i] = a[i];else x[i] = s, y[i] = a[i] - s; //这里x 和 y 没有固定大小关系,但一定是上下界}dp[1][0] = dp[1][1] = 0;fore(i, 2, n + 1){dp[i][0] = std::min(dp[i - 1][0] + y[i - 1] * x[i], dp[i - 1][1] + x[i - 1] * x[i]);dp[i][1] = std::min(dp[i - 1][0] + y[i - 1] * y[i], dp[i - 1][1] + x[i - 1] * y[i]);}std::cout << dp[n][0] << endl;}return 0;
}