CF-ER63-D-最大子段和变形

题目大意:

给你一个序列。你可以选择一段子序列让里面每个数 ∗ x *x x.问你最大字段和 。

题目思路:

答案要么是:原序列最大子段和。要么:

暴力 n 2 n^2 n2枚举这个子序列的位置.计算结果。再拼接上左右两端的最大字段和.即为结果。

现在考虑优化:

我们发现最终答案区间一定分三段,第一段是以 L − 1 L-1 L1为结尾的最大字段和,第二段 [ L , R ] [L,R] [L,R]是每个数相加*x,第三段也是以 R + 1 R+1 R+1开头的最大字段和。所以用状态机模型,分三个阶段进行.

d p ( i , 1 / 2 / 3 ) dp(i,1/2/3) dp(i,1/2/3)代表第 i i i个位置且当前为答案区间的第j段时的最大区间和。转移即可。

但是说实话,真的这题挺难想的.

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<ll,ll>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
ll a[maxn] , dp[maxn][3];
int main()
{
    
    
    ios::sync_with_stdio(false);
    int n , x; cin >> n >> x;
    for (int i = 1 ; i <= n ; i++)
        cin >> a[i];
    ll ans = 0;
    for (int i = 1 ; i <= n ; i++){
    
    
        dp[i][0] = max(dp[i - 1][0] , 0ll) + a[i];
        dp[i][1] = max(max(dp[i - 1][0],dp[i - 1][1]) , 0ll) + x * a[i];
        dp[i][2] = max(max(dp[i - 1][0],max(dp[i - 1][1] , dp[i - 1][2])) , 0ll) + a[i];
        ans = max(ans , max(dp[i][0] , max(dp[i][1] , dp[i][2])));
    }
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/114376177