題目鏈結
【題目描述】洛谷1115最大連續子串行求和暴力列舉o(n3)給出一段序列,選出其中連續且非空的一段使得這段和最大。
【輸入格式】
第1行是乙個正整數n(n≤200000),表示了序列的長度。
第2行包含n個絕對值不大於10000的整數a[i],描述了這段序列。
【輸出格式】
輸出僅包括1個整數,為最大的子段和是多少。子段的最小長度為1。
列舉——優化o(n2)
列舉——再優化o(n)
分治o(nlog2n)
動態規劃o(n)
對於此問題的求解與優化,讓人不得不折服於演算法的魅力我就是這麼入坑的。
大多數題目不出意外第一想法基本都是列舉;對於這個題目的暴力其實不難想到,題目求解的是乙個連續區間的和,區間必然有左右端點,因此直接列舉左端點l和右端點r,知道區間了求和還不是分分鐘的事(迴圈累加唄),**大概長得如下:
其實很多演算法不需要實現,通過時空複雜度分析即可;不難看出該演算法時間複雜度高達o(n3),,當n規模超過1000就會tle。不過該演算法還可以通過「字首和」優化。for
(int l=
1;l<=n;l++
)//列舉左端點
for(
int r=l;r<=n;r++
)
字首和:與陣列arr宣告乙個一樣大的陣列sum,將arr的前i項和儲存到sum[i],不難得到sum[i]=sum[i-1]+arr[i]
例如:123
4567
8arr13
-342-2
7-3sum141
57512
9應用字首和求解arr[ l到r ]的和:
sum[r]-sum[l-1] = arr[l]+arr[l+1]+……+arr[r]
因此,可以先預處理出字首和,然後用sum[r]-sum[l-1]代替for l to r求和;可優化到o(n2)。分析後發現該時間複雜度依然不能滿足題目要求,當然字首和思想還是不錯的,**大概如下:
列舉演算法至此,似乎已經山窮水盡呢,因為區間必然有左右端點,似乎最少也得兩個迴圈,也就是說最少也得o(n2)。sum[0]
=0;for
(int i=
1;i<=n;i++
)sum[i]
=sum[i-1]
+arr[i]
;for
(int l=
1;l<=n;l++
)for
(int r=l;r<=n;r++
) ans=
max(ans,sum[r]
-sum[l-1]
);
事實上,並非如此,在字首和的基礎上,可以再優化。
再上述演算法中不難看出核心**就一句:
如果我們固定r,那麼這句話可以理解為,找到乙個最好的左端點,使得最終的和最大。ans=
max(ans,sum[r]
-sum[l-1]
)
顯然,r固定後,sum[r]是不會改變的,因此要使sum[r]-sum[l-1]盡量大,只要找到最小的sum[l-1]即可。
因此,列舉右端點r,並維護乙個前r項的最小和mins即可。可省去列舉左端點的迴圈,從而將演算法優化到o(n)。
分治思想:大事化小,小事化了。#include
using
namespace std;
const
int n=
2e5+5;
int sum[n]
,ans=
-n,n,mins=0;
intmain()
printf
("%d"
,ans)
;return0;
}
假設要求解的區間為[l,r],l,r的重點為mid,而且最大和的那一段為[x,y],則[x,y]與mid只有三種關係:
[x,y]完全處於mid左邊,即x≤y[x,y]橫跨mid,即x[x,y]完全位於mid右邊,midx
對於第1種和第3種情況,顯然是乙個子問題。大問題是求解[l,r]中的[x,y],情況1和情況3是求解[l,mid]和[mid+1,r]中的[x,y];因此屬於規模更小的子問題,直接遞迴求解即可。
再看情況2,橫跨mid,則表明最優解一定是mid左邊一部分,右邊一部分,因此只需要求出以mid結尾的最優左子段lsum,以及mid+1的最優右欄位rsum,lsum+rsum就是第2種情況的最優解。
最後,返回三種情況中的最大值即可。
動態規劃求解此題是乙個經典演算法,決策也很簡單,因為對於數字arr[i],它只有兩種選擇:#include
using
namespace std;
const
int n=
2e5+6;
int arr[n]
,n;int
getmax
(int l,
int r)
intmain()
狀態方程也比較容易,f(i)表示以第i個數結尾的最大連續子串行的 和
對於數字i的決策:
狀態轉移方程:f(i)=max(f[i-1],0)+arr[i]
只需要掃瞄一次arr[i],因此時間複雜度為o(n),當然仔細分析會發現陣列arr其實以不要。因為只用了一次,完全可以直接用f[i]代替arr[i]
乙個題目從不同的角度出發,可能會有不同的解法。#include
const
int n=
2e5+6;
int f[n]
,n,ans=
-2e+9;;
intmain()
printf
("%d"
,ans)
;}
一種演算法是否可行,不一定要實現,通過分析就能知道大概。
有時候正解可能是在某個暴力演算法的基礎上優化而來(解法3),這個優化可能是某種思想(極大,極小,倍增,差分),也有可能需要採用一切特殊的資料結構(堆或 優先佇列,單調佇列,樹狀陣列,線段樹,st表)。
最大連續子串行求和
time limit 1 s memory limit 32 mb submitted 120 accepted 67 64bit integer format lld submit 給定k個整數的序列,其任意連續子串行可表示為,其中 1 i j k。最大連續子串行是所有連續子串行中元素和最大的乙個...
最大連續子串行求和
問題 有一串 int 數字串,存在陣列a中。要求找到起始位置start和終止位置end,使得從start位置到end位置的所有數字之和最大,返回這個最大值max。演算法思路 設 suffer 為以a x 終止且包含a x 的最大序列的和,有 if suffer a x 1 max suffer a ...
最大連續子串行求和
hz偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了 在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如 連續子向量的最大和為8 從第0個開始,到第...