zoukankan      html  css  js  c++  java
  • 51nod 1254 最大子段和 V2(递推)

    http://www.51nod.com/Challenge/Problem.html#problemId=1254

    最终答案只有2种情况
    1、不交换最大,相当于随便交换2个在最大子段和里的数。
    2、把一个原本不在最大子段和里的数换到最大子段和里。

    第1种情况就跑一遍求最大子段和就好
    对于第2种情况:
    假设现在要交换第i个和第k个 (k < i),并且第k个是我们想要的,第i个是要换走的。
    定义(g[i])表示把(a[i])(a[k])交换之后,以新的第i个数为最后一个数字的最大子段和
    定义(r[i])表示以i为第一个数字的最大子段和
    那么在交换的2个数是换走后一个、选用前一个的前提下,最大子段和可以表示为(max(g[i]+r[i+1]))
    对于 i > k 的情况,也就是交换的2个数是换走前一个、选用后一个,把a数组逆序再做一遍即可。

    如何快速求出(g[i]) ?
    (g[i]=max_{k=1}^{i-2}(a[k] + max_{h=k+1}^{i-1}(sum_{j=h}^{i-1}a[j]))), 子段长度 (leq) 2
    (g[i]=max_{j=1}^{i-1} a[j]),子段长度 (=1)
    所以
    (g[i+1]=max(max_{k=1}^{i-1}(a[k]+max_{h=k+1}^i(sum_{j=h}^ia[j])),max_{j=1}^i a[j])=max(g[i]+a[i],max_{j=1}^i a[j]))

    #include<cstdio>
    #include<algorithm>
    
    using namespace std;
    
    #define N 500003
    
    int n,a[N];
    long long r[N];
    long long ans=-1e17;
    
    void solve()
    {
    	for(int i=n;i;--i) r[i]=max(0ll,r[i+1]+a[i]);
    	int m=a[1];
    	long long g=a[1];
    	for(int i=2;i<=n;++i) 
    	{
    		ans=max(ans,g+r[i+1]);
    		m=max(m,a[i]);
    		g=max(g+a[i],1ll*m);
    	}
    }
    
    int main()
    {
    	scanf("%d",&n);
    	long long now=0;
    	for(int i=1;i<=n;++i) 
    	{
    		scanf("%d",&a[i]);
    		now+=a[i];
    		if(now<0) now=0;
    		ans=max(ans,now);
    	}
    	solve();
    	int t=n/2;
    	for(int i=1;i<=t;++i) swap(a[i],a[n-i+1]);
    	solve();
    	printf("%lld",ans);
    }
    
    作者:xxy
    本文版权归作者和博客园共有,转载请用链接,请勿原文转载,Thanks♪(・ω・)ノ。
  • 相关阅读:
    iptables的state模块的4种封包链接状态
    添加网络设备eth0
    DOM对象与jquery对象有什么不同
    A Death in the Family May Cause Real Heart Break
    A Soft Body, but the Mind of a Robot
    Oeasy系列教程
    浏览器中的javascript
    递归算法详细分析
    Axure 运行开发工具
    Hello Mono 转载的Mono Project Tutorial
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/14659526.html
Copyright © 2011-2022 走看看