原題:
D. Beautiful Array
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given an array a
consisting of n integers. Beauty of array is the maximum sum of some consecutive subarray of this array (this subarray may be empty). For example, the beauty of the array [10, -5, 10, -4, 1] is 15, and the beauty of the array [-3, -5, -1] is 0.
You may choose at most one consecutive subarray of a and multiply all values contained in this subarray by x.
You want to maximize the beauty of array after applying at most one such operation.
Input
The first line contains two integers n
and x (1≤n≤3⋅10^5,−100≤x≤100) — the length of array a and the integer x
respectively.
The second line contains n
integers a1,a2,…,an (−10^ 9≤ai≤10^9) — the array a.
Output
Print one integer — the maximum possible beauty of array a
after multiplying all values belonging to some consecutive subarray x.
Examples
Input
5 -2
-3 8 -2 1 -6
Output
22
Input
12 -3
1 3 3 7 1 3 3 7 1 3 3 7
Output
42
Input
5 10
-1 -2 -3 -4 -5
Output
0
Note
In the first test case we need to multiply the subarray [-2, 1, -6], and the array becomes [-3, 8, 4, -2, 12] with beauty 22 ([-3, 8, 4, -2, 12]).
In the second test case we don’t need to multiply any subarray at all.
In the third test case no matter which subarray we multiply, the beauty of array will be equal to 0.
中文:
給你n個整數a[i],然後給你一個數x,你可以將其中某個連續的子段乘上x,只能乘一次,現在讓你求這個序列的最大字段和。
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn=300005;
typedef long long ll;
ll v[maxn];
ll dp[maxn][3];
int n, x;
int main()
{
ios::sync_with_stdio(false);
while (cin >> n >> x)
{
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
cin >> v[i];
ll ans = 0;
for (int i = 1; i <= n; i++)
{
dp[i][0] = max(dp[i - 1][0] + v[i], v[i]);
ans = max(ans, dp[i][0]);
dp[i][2] = max(dp[i - 1][0] + v[i] * x, max(dp[i - 1][2] + v[i] * x, v[i] * x));
ans = max(ans, dp[i][2]);
dp[i][1] = max(dp[i - 1][1] + v[i], dp[i - 1][2] + v[i]);
ans = max(ans, dp[i][1]);
}
cout << ans << endl;
}
//system("pause");
return 0;
}
思路:
很不錯的一道最大子段和的改進題目。
原始的最大字段和的求解策略如下
設置 表示計算前i個數時計算最大子段和的狀態(注意最大字段和地推的過程中每次得到的並非爲當前的最優解)
由於時最大字段和,那麼當前下標的數值時必須要取的,那麼狀態轉移的情況有兩種,分別是隻取當前的a[i]作爲計算到的最大狀態,以及將加到之前累加的序列上
這道題目當中可以對計算過程中的任意一個序列乘以一個數
假設先考慮有兩種情況
其中僅記錄不對任何一個子序列乘以時得到的最優結果,即原始的最大字段和
那麼就需要記錄序列乘以的結果,這樣才能不漏解
狀態轉移方程需要考慮的情況如下
如果在之前就已經有乘以某一個序列了,那麼當前的值需要考慮兩種情況
一種是直接加到狀態上,即
另一種是需要將也乘上一個,但是這種情況有個問題,因爲只能被乘上一次;
如果這個數已經被乘過了,那麼可以直接乘以,即與之前的序列連在一起乘上,表示爲;(1)
如果是在之前乘過的,需要把上次乘過的取消掉,可以表示爲。(2)
上面的遞推關係有個問題,你怎麼知道(1)上一步的狀態是不是乘過?
這裏解決辦法爲添加一個狀態,將問題分解。
重新定義狀態與
其中表示在之前乘過,但是在第個狀態沒有乘過
表示第i個狀態正在乘以,後面可以接上
那麼狀態轉移方程就可以寫成如下的三個形式,不漏掉任何一個解