cf Educational Codeforces Round 63 D. Beautiful Array

原題:

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;
    }

思路:

很不錯的一道最大子段和的改進題目。

原始的最大字段和的求解策略如下

設置 dp[i]dp[i]表示計算前i個數時計算最大子段和的狀態(注意最大字段和地推的過程中每次得到的dp[i]dp[i]並非爲當前的最優解)
由於時最大字段和,那麼當前下標的數值時必須要取的,那麼狀態轉移的情況有兩種,分別是隻取當前的a[i]作爲計算到dp[i]dp[i]的最大狀態,以及將a[i]a[i]加到之前累加的序列上dp[i1]+a[i]dp[i-1]+a[i]

這道題目當中可以對計算過程中的任意一個序列乘以一個數xx

假設先考慮有兩種情況
dp[i][2]dp[i][2]
其中dp[i][0]dp[i][0]僅記錄不對任何一個子序列乘以xx時得到的最優結果,即原始的最大字段和
那麼dp[i][1]dp[i][1]就需要記錄序列乘以xx的結果,這樣才能不漏解
狀態轉移方程需要考慮的情況如下

如果在dp[i][1]dp[i][1]之前就已經有xx乘以某一個序列了,那麼當前的值a[i]a[i]需要考慮兩種情況

一種是直接加到狀態dp[i1][1]dp[i-1][1]上,即dp[i1][1]+a[i]dp[i-1][1]+a[i]
另一種是需要將a[i]a[i]也乘上一個xx,但是這種情況有個問題,因爲xx只能被乘上一次;

如果a[i1]a[i-1]這個數已經被乘過xx了,那麼a[i]a[i]可以直接乘以xx,即與之前的序列連在一起乘上xx,表示爲dp[i][1]=dp[i1][1]+a[i]xdp[i][1]=dp[i-1][1]+a[i]*x;(1)

如果xx是在a[i1]a[i-1]之前乘過的,需要把上次乘過的xx取消掉,可以表示爲dp[i][1]=dp[i1][0]+a[i]xdp[i][1]=dp[i-1][0]+a[i]*x。(2)

上面的遞推關係有個問題,你怎麼知道(1)上一步的狀態是不是乘過xx

這裏解決辦法爲添加一個狀態,將問題分解。
重新定義狀態dp[i][1]dp[i][1]dp[i][2]dp[i][2]
其中dp[i][1]dp[i][1]表示在ii之前乘過xx,但是在第ii個狀態沒有乘過
dp[i][2]dp[i][2]表示第i個狀態正在乘以xx,後面可以接上a[i]xa[i]*x

那麼狀態轉移方程就可以寫成如下的三個形式,不漏掉任何一個解

dp[i][0]=max(dp[i1][0]+a[i],a[i]); dp[i][0] = max(dp[i - 1][0] + a[i], a[i]);

dp[i][2]=max(dp[i1][0]+a[i]x,max(dp[i1][2]+a[i]x,a[i]x)); dp[i][2] = max(dp[i - 1][0] + a[i] * x, max(dp[i - 1][2] + a[i] * x, a[i] * x));

dp[i][1]=max(dp[i1][1]+a[i],dp[i1][2]+a[i]); dp[i][1] = max(dp[i - 1][1] + a[i], dp[i - 1][2] + a[i]);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章