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

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

猜你喜欢

转载自www.cnblogs.com/VIrtu0s0/p/10812413.html