1. 程式人生 > >Educational Codeforces Round 63 (Rated for Div. 2) D dp(最大連續子序列)

Educational Codeforces Round 63 (Rated for Div. 2) D dp(最大連續子序列)

pre Education -- tps ont fine ble ted ()

https://codeforces.com/contest/1155/problem/D

題意

一個n個數的數組\(a[i]\),可以選擇連續的一段乘x,求最大連續子序列的值

題解

  • 錯誤思路:貪心,假如x<0,那麽就選擇最小的一段乘以x,再求最大連續子序列,因為這一段可能夾著一些很大的正數使得翻轉一整段的代價很大,可能單獨翻轉前半段或者後半段更好
  • 定義\(f[i]\)為以i結尾的最大連續子序列,\(g[i]\)為以i開頭的最大連續子序列
  • 假設選擇翻轉的區間是(l,r),則有\(ans=max(f[l]+g[r+1]+sum[r]-sum[l])\)
  • 移項得:\(sum[r]+g[r+1]+f[l]-sum[l]\)
    ,可以枚舉r,然後維護最大的\(f[l]-sum[l]\)即可

代碼

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
ll x[300005],sum[300005],f[300005],g[300005],ans,mx;
int n,X;
int main(){
    cin>>n>>X;
    for(int i=1;i<=n;i++){
        scanf("%lld",&x[i]);
        sum[i]=sum[i-1]+x[i];
        f[i]=max(x[i],f[i-1]+x[i]);
    }
    for(int i=n;i>=1;i--)
        g[i]=max(g[i+1]+x[i],x[i]);
    for(int r=0;r<=n;r++){
        ans=max(ans,mx+max(0ll,g[r+1])+sum[r]*X);
        mx=max(mx,max(0ll,f[r])-sum[r]*X);
    }
    cout<<ans;
} 

Educational Codeforces Round 63 (Rated for Div. 2) D dp(最大連續子序列)