zoukankan      html  css  js  c++  java
  • 51nod1524 最大子段和V2

    题干

    N个整数组成的序列a[1],a[2],a[3],…,a[n],你可以对数组中的一对元素进行交换,并且交换后求a[1]至a[n]的最大子段和,所能得到的结果是所有交换中最大的。当所给的整数均为负数时和为0。
    例如:{-2,11,-4,13,-5,-2, 4}将 -4 和 4 交换,{-2,11,4,13,-5,-2, -4},最大子段和为11 + 4 + 13 = 28。

    Input
    第1行:整数序列的长度N(2 <= N <= 50000) 第2 - N + 1行:N个整数(-10^9 <= A[i] <= 10^9)
    Output
    输出交换一次后的最大子段和。
    Sample Input

    7
    -2
    11
    -4
    13
    -5
    -2
    4
    

    Sample Output

    28
    

    一点题外话

    这道题真的很不起眼qwq

    一开始做的时候各位大佬都是各显神通,然鹅结果不如人意,然后去网上找题解,结果题解里的显然显然不是那么正确...(https://www.cnblogs.com/hbhszxyb/p/13130945.html)。

    能AC完全是数据水,于是狠狠地暴露了一波,还好咱当时就是没看懂那个显然就没抄那个代码qwq(然后就恬不知耻地抄了另一个)

    最后还是听虎哥讲听明白了,难受

    开始整活

    思路来自:https://blog.csdn.net/zlh_hhhh/article/details/78176629 (膜拜大佬)

    首先,我们交换有三种情况,一是交换的两个数都在最优子段内,二是交换的两个数都不在最优子段内,三是一个在最优子段内一个不在

    显然,前两种对我们的答案没有什么影响,我们需要处理的就是第三种。

    虎哥说:“如果一道题怎么都没有思路,那么就把它当成DP来做”

    于是,我们先不考虑复杂度的问题,从DP的方向来想。

    我们先从左到右遍历,遍历到 (i),我们假设把左边的某一个数 (a[k])(a[i]) 替换。

    然后定义两个式子,1为此时新的a[i]向左延伸能得到的最大子段和,2为 (a[i+1]) 向右延伸能得到的最大子段和,那么显然我们的答案就是1式加2式,然后不断往下遍历取最优。

    2式很简单,我们可以通过预处理直接得到,问题在于1式,这里就要用DP来考虑一下。

    我们记遍历到第i位时的1式为 (G[i])

    那么我们的思路就是跟着定义走,枚举到 (i),然后从1往右枚举 (k),交换,然后判断此时向左延伸的最大子段和,取最优,式子写出来是:

    (G[i]=max_{k=1}^{i-2}ig( A[k]+max_{t=k+1}^{i-1}(sum_{j=t}^{i-1}A[j])ig))

    可能有神犇注意到这个式子并不完全,因为我们只枚举到了 (i-2),为什么不能枚举到 (i-1) 呢?

    很显然,枚举到 (i-2),意味着我们向左延伸的最大子段和的长度至少为2。如果长度为1,那么此时

    (max_{t=k+1}^{i-1}(sum_{j=t}^{i-1}A[j])) 显然是不执行的。

    所以我们的式子只剩下: (G[i]=max_{k=1}^{i-1}ig( A[k]))

    (k) 此时等于 (i-1) ,所以实际上我们的选择被固定在 (a[i-1]) 这一个数上,所以此时长度为1的最大子段和就是 (a[i-1])

    而这显然不正确,如果长度大于等于2,因为考虑到子段的顺序问题,那么照上边那么做是没问题的,但我们此时长度为1,显然我们可以直接从左边找一个最大值过来换掉 (a[i]),而不一定是 (a[i-1]),所以我们需要特判一下长度为1的情况。

    我们记:(M[i-1]=max_{k=1}^{i-1}A[k])

    于是就有了:

    [G[i]=maxBig(max_{k=1}^{i-2}ig( A[k]+max_{t=k+1}^{i-1}(sum_{j=t}^{i-1}A[j])ig),M[i-1]Big) ]

    照猫画虎,就有了:

    [G[i+1]=maxBig(max_{k=1}^{i-1}ig( A[k]+max_{t=k+1}^{i}(sum_{j=t}^{i}A[j])ig),M[i]Big) ]

    我们试着改写一下:

    [G[i+1]=maxBig(max_{k=1}^{i-1}ig( A[k]+max_{t=k+1}^{i}(sum_{j=t}^{i}A[j])ig),M[i]Big ) ]

    [=maxBig(max_{k=1}^{i-2}ig( A[k]+max_{t=k+1}^{i-1}(sum_{j=t}^{i-1}A[j]) )+A[i],M[i]Big ) ]

    这个改写其实是不正确的,因为我们知道(max_{k=1}^{i-2}ig( A[k]+max_{t=k+1}^{i-1}(sum_{j=t}^{i-1}A[j]))其实是(G[i])的长度至少为2的部分,在加上上边我们提出来这个 (a[i]),就变成了 (G[i+1]) 长度至少为3的部分,而 (M[i]) 是长度为1的部分,显然我们缺少了长度为2的部分,那么解决也很简单,直接在判断里加上就好了。

    所以,最后的结果是:

    [G[i+1]=maxBig(max_{k=1}^{i-2}ig( A[k]+max_{t=k+1}^{i-1}(sum_{j=t}^{i-1}A[j]) )+A[i],M[i-1]+A[i],M[i]Big) ]

    [G[i+1]=max(G[i]+A[i],M[i-1]+a[i],M[i]) ]

    递推式有了,代码就比较容易了,还有就是注意我们从左到右扫一边不能判断全部的情况,所以还要反着扫一边。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn = 50000 + 10;
    #define ll long long
    #define inf 0x3f3f3f3f
    
    int a[maxn], maxx = -inf; 
    ll sl[maxn], sr[maxn], ans = -inf;
    ll G1[maxn], G2[maxn];
    
    int main(){
    	int n;
    	cin >> n;
    	for(int i = 1; i <= n; i++){
    		scanf("%d", &a[i]);
    	}
    	for(int i = 1, j = n; i <= n; i++, j--){
    		sl[i] = sl[i-1] + a[i];
    		sr[j] = sr[j+1] + a[j]; // 保存以j为开始向右延伸的最大子段和
    		if(sl[i] < 0) sl[i] = 0;
    		if(sr[j] < 0) sr[j] = 0;
    		if(ans < sl[i]) ans = sl[i]; // 防止存在原始的最大子段和就是最优解的情况,这是存在的,因为我们可以选择交换组合内的两个数
    	}
    	maxx = a[1];
    	for(int i = 2; i <= n; i++){
    		G1[i] = G1[i-1] + a[i-1];
    		if(G1[i] < maxx) G1[i] = maxx;
    		if(ans < G1[i] + sr[i+1]) ans = G1[i] + sr[i+1];
    		if(maxx < a[i]) maxx = a[i];
    	}
    	maxx = a[n];
    	for(int i = n - 1; i > 0; i--){
    		G2[i] = G2[i+1] + a[i+1];
    		if(G2[i] < maxx) G2[i] = maxx;
    		if(ans < G2[i] + sl[i-1]) ans = G2[i] + sl[i-1];
    		if(maxx < a[i]) maxx = a[i];
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    164.Maximum Gap
    163.Missing Ranges
    162.Find Peak Element
    161.One Edit Distance
    160.Intersection of Two Linked Lists
    7.5爬取猫眼Top100电影名单
    7.5文件操作
    7.4文件操作(1)
    7.4一个失败的网易云爬虫,
    7.3数据结构(1)
  • 原文地址:https://www.cnblogs.com/Zfio/p/13125805.html
Copyright © 2011-2022 走看看