您的位置:首页 > 其它

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

2015-08-15 23:53 190 查看
惯例先贴题目:西电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循环扫描一遍。

for(int 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: