翻译
RSJ有一个包含 n n n个整数 a 1 , a 2 , … , a n a_1,a_2, \ldots, a_n a1,a2,…,an和一个整数 s s s的序列 a a a。对于 a 2 , a 3 , … , a n − 1 a_2, a_3, \ldots, a_{n-1} a2,a3,…,an−1中的每个元素,他选择了一对非负整数 x i x_i xi和 y i y_i yi,使得 x i + y i = a i x_i+y_i=a_i xi+yi=ai且 ( x i − s ) ⋅ ( y i − s ) ≥ 0 (x_i-s) \cdot (y_i-s) \geq 0 (xi−s)⋅(yi−s)≥0。
现在他想要计算如下值:
F = a 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_2+y_2 \cdot x_3+y_3 \cdot x_4 + \ldots + y_{n - 2} \cdot x_{n-1}+y_{n-1} \cdot a_n. F=a1⋅x2+y2⋅x3+y3⋅x4+…+yn−2⋅xn−1+yn−1⋅an.
请帮助他通过选择 x i x_i xi和 y i y_i yi的最佳值,找到可能的最小值 F F F。可以证明至少存在一种有效的选择方法。
输入
每个测试包含多个测试用例。第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104) —— 测试用例的数量。
每个测试用例的第一行包含两个整数 n n n和 s s s ( 3 ≤ n ≤ 2 ⋅ 1 0 5 3 \le n \le 2 \cdot 10^5 3≤n≤2⋅105; 0 ≤ s ≤ 2 ⋅ 1 0 5 0 \le s \le 2 \cdot 10^5 0≤s≤2⋅105)。
第二行包含 n n n个整数 a 1 , a 2 , … , a n a_1,a_2,\ldots,a_n a1,a2,…,an ( 0 ≤ a i ≤ 2 ⋅ 1 0 5 0 \le a_i \le 2 \cdot 10^5 0≤ai≤2⋅105)。
保证 n n n的总和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105。
输出
对于每个测试用例,打印 F F F的可能的最小值。
注意
在第一个测试用例中, 2 ⋅ 0 + 0 ⋅ 1 + 0 ⋅ 3 + 0 ⋅ 4 = 0 2\cdot 0+0\cdot 1+0\cdot 3+0\cdot 4 = 0 2⋅0+0⋅1+0⋅3+0⋅4=0。
在第二个测试用例中, 5 ⋅ 1 + 2 ⋅ 2 + 2 ⋅ 2 + 1 ⋅ 5 = 18 5\cdot 1+2\cdot 2+2\cdot 2+1\cdot 5 = 18 5⋅1+2⋅2+2⋅2+1⋅5=18。
思路
易知:
x
i
>
=
s
,
y
i
>
=
s
x_i~>=~s,~y_i >= s
xi >= s, yi>=s 或
x
i
<
=
s
,
y
i
<
=
s
x_i~<=~s,~y_i <= s
xi <= s, yi<=s。
由于需要得到最小的
F
F
F,所以
F
F
F 右边的乘积式中的因子的差要尽可能大。
所以
a
i
a_i
ai 分成的
x
i
,
y
i
x_i,~y_i
xi, yi 一定满足其中一个是最大值,另外一个是最小值。
即对于每个
i
∈
[
2
,
n
−
1
]
i ∈[2, n - 1]
i∈[2,n−1] 进行dp(
x
i
x_i
xi 和
y
i
y_i
yi 中哪个取最大、哪个取最小)。
C o d e Code Code
#include <bits/stdc++.h>
#define int long long
#define sz(a) ((int)a.size())
using namespace std;
using PII = pair<int, int>;
using i128 = __int128;
const int N = 2e5 + 10;
int n, s;
int a[N];
void solve() {
cin >> n >> s;
for (int i = 1; i <= n; i ++) cin >> a[i];
vector <array<int, 2>> f(n + 1, {0, 0});
// dp数组,f[i][0]:x_i取最小,y_i取最大
vector <int> imin(n + 1, 0), imax(n + 1, 0);
for (int i = 1; i <= n; i ++) {
if (a[i] >= 2 * s) { // x_i、y_i都 >= s
imin[i] = s;
imax[i] = a[i] - s;
} else { // x_i、y_i都 <= s
imax[i] = min(a[i], s);
imin[i] = a[i] - imax[i];
}
}
f[2][0] = a[1] * imin[2];
f[2][1] = a[1] * imax[2];
for (int i = 3; i <= n - 1; i ++) {
f[i][0] = min(f[i - 1][0] + imax[i - 1] * imin[i], f[i - 1][1] + imin[i - 1] * imin[i]);
f[i][1] = min(f[i - 1][0] + imax[i - 1] * imax[i], f[i - 1][1] + imin[i - 1] * imax[i]);
}
cout << " ";
cout << min(f[n - 1][0] + imax[n - 1] * a[n], f[n - 1][1] + imin[n - 1] * a[n]) << "\n";
// 注意:最后的y_n-1 + a[n]不能在上边那个for循环中进行,
// 因为n <= 3的时候是无法进入循环的!
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t; cin.get();
while (t --) solve();
return 0;
}