最大连续子序列和(xdoj 1079)

本文介绍了最大连续子序列和问题的解决方案,给出了标准算法的时间复杂度为O(n),并提供了两种不同的思路和代码实现。针对特殊情况,如数据中存在多个相同最大或最小值的情况,文章详细解释了如何判断和处理,确保求得正确结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

惯例先贴题目:西电oj 1079 http://acm.xidian.edu.cn/problem.php?id=1079

最大连续子序列和的标准算法:时间复杂度o(n)
设所给序列为a[n]
定义sum[i]为以i结尾的最大连续子区间和,
易找到递推关系sum[i]=max(0,sum[n-1])+a[i]
所以只需要用for循环扫描一遍。

forint i=1;i<=n;i++)
{
    last=max(0,last)+a[i];
    ans=max(ans,last);
}

若上面的代码不好理解,你也可以写成这样,一样的思路和复杂度

int sum=0,max=0;
for(int i=0;i<n;i++)
{
    if(sum<0)
        sum=a[i];
    else 
        sum+=a[i];
    if(sum>max)
    max=sum;
}

下面是1079的题解

这个题首先需要两层for循环枚举子序列中最多的数和最少的数。
设最多的数为i,最少的数为j
然后处理原数组
原数组中==i的数处理成1,==j的数处理成-1,其他数处理成0;
然后求最大子序列和就是最大差值 //每出现一次最多的数,差值+1,每出现一次最少的数,差值-1
不过这里需要注意如果是这样的数据:1 0 1 1 1 1 1
上述方法得到的值是6,明显是错误的
所以需要判断。
如果得到的子序列中存在-1,那么求得的差就是所求的差
如果得到的子序列中不存在-1,且整个数列中不存在-1,那么这时的差=0,因为只出现了一个数,没有可比性
如果得到的子序列中不存在-1,且整个数列中存在-1,那么这时的差-1就是所求。

下面是代码

#include <bits/stdc++.h>
using namespace  std;

int mm[100005],ll[100005];

int solve(int duo,int shao,int n)
{
    int ma=0,ans=0,flag=0,flagg=0,e=0,f=0,ee=0,ff=0;
    for(int i=0;i<n;i++)
    {
        if(mm[i]==duo)
           ll[i]=1;
        else if(mm[i]==shao)
           ll[i]=-1;
        else ll[i]=0;
    }
    for(int j=0;j<n;j++)
    {
        if(ll[j]==-1)
           flag++;
        if(ans<0)
        {
            ans=ll[j];
            e=j;
            f=j;
            flag=0;
            if(ll[j]==-1)
              flag=1;
        }
        else
        {
            ans+=ll[j];
            e++;
        }
        if(ans>ma || (ans==ma&&flagg<1))
        {
            ma=ans;
           ff=f;
           ee=e;
           flagg=flag;
        }
    }
    if(flagg)
        return  ma;
    for(int k=ff;k>=0;k--)
    {
                if(ll[k]==-1)
                    return ma-1;
    }
   for(int h=ee;h<n;h++)
    {
                if(ll[h]==-1)
                    return ma-1;
    }
    return 0;
}

int main() 
{
    int T,ma=0;
    scanf("%d",&T);
    while(T--)
    {
        ma=0;
        int m,n;
        scanf("%d %d",&n,&m);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&mm[i]);
        }
        for(int j=1;j<=m;j++)
        for(int k=1;k<=m;k++)
        {
            if(j!=k)
            {
                ma=max(ma,solve(j,k,n));
            }
        }
        printf("%d\n",ma);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值