慣例先貼題目:西電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;
}