C. Remove the Bracket
C. Remove the Bracket
RSJ has a sequence $a$ of $n$ integers $a_1,a_2, \ldots, a_n$ and an integer $s$. For each of $a_2,a_3, \ldots, a_{n-1}$, he chose a pair of non-negative integers $x_i$ and $y_i$ such that $x_i+y_i=a_i$ and $(x_i-s) \cdot (y_i-s) \geq 0$.
Now he is interested in the value $$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.$$
Please help him find the minimum possible value $F$ he can get by choosing $x_i$ and $y_i$ optimally. It can be shown that there is always at least one valid way to choose them.
Input
Each test contains multiple test cases. The first line contains an integer $t$ ($1 \le t \le 10^4$) — the number of test cases.
The first line of each test case contains two integers $n$, $s$ ($3 \le n \le 2 \cdot 10^5$; $0 \le s \le 2 \cdot 10^5$).
The second line contains $n$ integers $a_1,a_2,\ldots,a_n$ ($0 \le a_i \le 2 \cdot 10^5$).
It is guaranteed that the sum of $n$ does not exceed $2 \cdot 10^5$.
Output
For each test case, print the minimum possible value of $F$.
Example
input
10 5 0 2 0 1 3 4 5 1 5 3 4 3 5 7 2 7 6 5 4 3 2 1 5 1 1 2 3 4 5 5 2 1 2 3 4 5 4 0 0 1 1 1 5 5 4 3 5 6 4 4 1 0 2 1 0 3 99999 200000 200000 200000 6 8139 7976 129785 12984 78561 173685 15480
output
0 18 32 11 14 0 16 0 40000000000 2700826806
Note
In the first test case, $2\cdot 0+0\cdot 1+0\cdot 3+0\cdot 4 = 0$.
In the second test case, $5\cdot 1+2\cdot 2+2\cdot 2+1\cdot 5 = 18$.
解题思路
这题一看这么多变量不好下手,实际上要想到把其他变量固定而只考虑某个变量的取值。具体来说就是,假设除$x_i$和$y_i$外其他的变量都是固定的值,再来求$F$的最小值。
这个就好求多了,其中$x_i$和$y_i$能够影响到的项只有$y_{i-1} x_{i} + y_{i} x_{i+1}$,而$y_i = a_i - x_i$,因此就有$y_{i-1} x_{i} + (a_i - x_i) x_{i+1}$。由于只有$x_i$是变量,因此可以发现这个一元线性函数,很明显要使得$y_{i-1} x_{i} + (a_i - x_i) x_{i+1}$取到最小值,那么$x_i$的取值一定是定义域的其中一个端点(此时$y_i$也是其定义域的一个端点)。
$x_i$的定义域就与$a_i$和$s$有关系了:
- 如果$a_i \leq s$,那么$0 \leq x_i \leq a_i$,因此要么是$x_i = 0, \ y_i = a_i$,要么是$x_i = a_i, \ y_i = 0$。
- 如果$a_i > s$,同理要么是$x_i = a_i - s, \ y_i = s$,要么是$x_i = s, \ y_i = a_i - s$。
因此可以发现,当其他变量固定时,要使得$F$取到最小值那么$x_i$和$y_i$应该取定义域的两个端点,有两种组合。剩下的就是枚举$2^n$种情况取最小值就可以了,因此可以考虑用状态机dp。
定义状态$f(i, 0)$和$f(i, 1)$,其中这里的$0$和$1$表示$x_i$和$y_i$取值的两种组合情况(第$1$种情况就是对第$0$种的$x_i$和$y_i$两两交换一下就可以了)。因此$f(i, 0)$就表示前$i$项和且$x_i,y_i$是第$0$种组合的最小值,同理$f(i, 1)$就表示前$i$项和且$x_i,y_i$是第$1$种组合的最小值。这里的前$i$项和是指$\sum\limits_{j=2}^{i} {y_{j-1}x_{j}}$。状态划分就根据第$i-1$项是哪种组合来转移就可以了,具体看状态转移方程:
\begin{cases}
f(i, 0) = \min\{ {f(i-1,0)} + y_{i-1} \cdot x_{i}, \ {f(i-1,1)} + x_{i-1} \cdot x_{i} \} \\
f(i, 1) = \min\{ {f(i-1,0)} + y_{i-1} \cdot y_{i}, \ {f(i-1,1)} + x_{i-1} \cdot y_{i} \}
\end{cases}
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 2e5 + 10; 7 8 LL x[N], y[N]; 9 LL f[N][2]; 10 11 void solve() { 12 int n, m; 13 scanf("%d %d", &n, &m); 14 for (int i = 1; i <= n; i++) { 15 LL v; 16 scanf("%lld", &v); 17 if (i == 1 || i == n) x[i] = y[i] = v; 18 else if (v <= m) x[i] = 0, y[i] = v; 19 else x[i] = v - m, y[i] = m; 20 } 21 for (int i = 2; i <= n; i++) { 22 f[i][0] = min(f[i - 1][0] + y[i - 1] * x[i], f[i - 1][1] + x[i - 1] * x[i]); 23 f[i][1] = min(f[i - 1][0] + y[i - 1] * y[i], f[i - 1][1] + x[i - 1] * y[i]); 24 } 25 printf("%lld\n", f[n][0]); 26 } 27 28 int main() { 29 int t; 30 scanf("%d", &t); 31 while (t--) { 32 solve(); 33 } 34 35 return 0; 36 }
参考资料
TypeDB Forces 2023 (Div. 1 + Div. 2, Rated, Prizes!) Editorial:https://codeforces.com/blog/entry/112009
TypeDB Forces 2023 (Div. 1 + Div. 2, Rated, Prizes!)(持续更新):https://www.cnblogs.com/cjjsb/p/17077371.html
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17079585.html