FZU - 2253 Salty Fish(最大子段和)

海边躺着一排咸鱼,一些有梦想的咸鱼成功翻身(然而没有什么卵用),一些则是继续当咸鱼。一个善良的渔夫想要帮这些咸鱼翻身,但是渔夫比较懒,所以只会从某只咸鱼开始,往一个方向,一只只咸鱼翻过去,翻转若干只后就转身离去,深藏功与名。更准确地说,渔夫会选择一个区间[L,R],改变区间内所有咸鱼的状态,至少翻转一只咸鱼。

渔夫离开后想知道如果他采取最优策略,最多有多少只咸鱼成功翻身,但是咸鱼大概有十万条,所以这个问题就交给你了!

Input
包含多组测试数据。

每组测试数据的第一行为正整数n,表示咸鱼的数量。

第二行为长n的01串,0表示没有翻身,1表示成功翻身。

n≤100000

Output
在渔夫的操作后,成功翻身咸鱼(即1)的最大数量。

Sample Input
5
1 0 0 1 0
3
0 1 0
Sample Output
4
2
Hint
对于第一个样例,翻转区间[2,3],序列变为1 1 1 1 0。

对于第二个样例,翻转整个区间,序列变为1 0 1。

分析:将连续整块的1和0压缩成一个数字,首先我们知道若对于一个块区间,如果全是1,那么肯定不能单独翻,如果一块区间全是0,那么可能可以全部翻过来,但是是否会和隔着的一块0区间一起翻过来的收获更大呢?也就是说,要如果翻,要么是一整块0区间翻,要么是010这样的区间翻,不会出现01或者10这样左边或右边是1的情况翻转。那么规整为单独的数字后,如果是0,说明翻过来肯定有这个区间长度的收获,如果是1,翻过来就有区间长度的减少。因此1的块收获为负数,0块收获为整数,对于一串有正有负的数列,我们选择连续的几个值求和使其价值最大,这就是最大子段和问题。

最大子段和问题: 给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。

于是,我们利用动态规划的方法以O(n)的复杂度算出最优结果。

如果当前取到的求和大于0,那么说明收获是正数,加上下一个数,即使下一个数可能是负数使收获减少,但难免再之后的数是更大的收获能把一段负值挽回。

而当前值为0或负值时,这样的情况没有延续下去或者用后面的值挽回的必要,直接舍去前面这段区间,取一个为正数的开头作为新区间。因为之前已经说明了,我们不会有一个10这样的开头,1是负值,取10的翻转区间不如取一个0的区间作为端点。

以这样的方式不断取值求和,其中一只记录这样区间取舍的最大值。即最终的ans。

注意题目要求必须翻一条鱼,不能不翻,因此全部是1的时候,要减去一个1的个数输出。

#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=1e5+10;
int a[maxn];
vector<int>q;
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        q.clear();
        int tmp=-1,one=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i])one++;
            if(tmp==-1)
            {
                tmp=1;
                continue;
            }
            if(i!=1&&a[i]!=a[i-1])
            {
                if(a[i-1])tmp=-tmp;
                q.push_back(tmp);
                tmp=1;
            }
            else tmp++;
        }
        if(a[n])tmp=-tmp;
        q.push_back(tmp);
        if(n==one)///必须翻一次
        {
            printf("%d\n",n-1);
            continue;
        }
        int ans=0;
        tmp=0;
        for(int i=0;i<q.size();i++)///最大子段和
        {
            if(tmp>0)tmp+=q[i];
            else tmp=q[i];
            if(tmp>ans)ans=tmp;
        }
        printf("%d\n",one+ans);
    }
}
posted @ 2018-06-10 18:14  KuroNekonano  阅读(140)  评论(0编辑  收藏  举报