• 最大子段和(交换)


    题意:

      给你一个序列找到交换一次后的最大字段和(所有交换方式中最大的)

    分析:

      首先我们这么想,我们要最后要的答案是由某个区间和区间左边交换一个或和区间右边交换一个或者不交换(内部交换或外部交换)。

      至于不交换,我们直接o(n)搞过。

      然后就是向左(向右类似,只要把序列倒过来跑一边就好了)交换,我们可以得到:ans=max(sum[i]-sum[j]-a[k1]+a[k2])(i>j,j<k1<=i,k2<=j),我们只要n的4次方枚举就好了。

      可是我们怎么优化呢?

      我们加一个括号:sum[i]-(sum[j]+a[k1]-a[k2])(范围略去),然后我们就可以n的效率枚举i,然后提前预处理一下min(sum[j]+a[k1]-a[k2]),用一个数组记录一下min(枚举合法的j,k1,k2),然后求一下前缀max就好了,效率到了n的3次方,然后类似的,我们只需要n的效率枚举k1,然后n×n求sum[j]-a[k2]的最小值,效率变成了n×n,最后再n的效率枚举j,n的效率求k2的最小值,效率变成了n,最后整合到一起就好了。

      代码:

      

    #include <cstdio>
    #include <string>
    using namespace std;
    #define ll long long
    const int maxn=5e4+10;
    const ll inf=1e18;
    
    ll a[maxn];
    ll sum[maxn];
    ll b[maxn];
    int main(){
        int n;
        scanf("%d",&n);
        ll mi=0ll,ans=-inf,nowj=0ll,ma=-inf;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            sum[i]=sum[i-1]+a[i];
            ans=max(ans,sum[i]-nowj);
            nowj=min(nowj,a[i]+mi);
            ma=max(ma,a[i]);
            mi=min(sum[i]-ma,mi);
        }
        mi=0ll;
        for(int i=1;i<=n;i++){
            ans=max(ans,sum[i]-mi);
            mi=min(sum[i],mi);
        }
        for(int i=1;i<=n;i++)
            b[i]=a[n-i+1];
        for(int i=1;i<=n;i++)
            a[i]=b[i];
        mi=0ll,nowj=0ll,ma=-inf;
        for(int i=1;i<=n;i++){
            sum[i]=sum[i-1]+a[i];
            ans=max(ans,sum[i]-nowj);
            nowj=min(nowj,a[i]+mi);
            ma=max(ma,a[i]);
            mi=min(sum[i]-ma,mi);
        }
        printf("%lld",ans);
        return 0;
    }

      

  • 相关阅读:
    Android学习路径(两)项目文件本身使用场景和文件演示
    A左右ndroid正在使用Uri监视数据库中的更改
    离PACKET_INp获取信息acket data
    curl 命令
    POJ 3177 Redundant Paths POJ 3352 Road Construction(双连接)
    Linux 下一个 Mysql error 2002 错误解决
    图片打水印 缩放 和一个输入流的转换
    qt Qt5开发
    qt 关于Qt中MVC的介绍与使用
    qt mvc3
  • 原文地址:https://www.cnblogs.com/wish-all-ac/p/13112002.html
Copyright © 2020-2023  润新知