COGS82 求子序列

2022-09-19 02:45:06 字數 1302 閱讀 2781

這是一道經典題目了,劉汝佳在紫書上講解了三種方法,複雜度從o(n3)->o(n2)->o(n)。

記得高一我寫這道題的時候迷迷糊糊的,對於o(n)的演算法並不是很理解,今天我重新寫這道題並用o(nlogn)的分治方法解決,也是為寫維護數列做準備。

divide and conquer 分而治之的思想可以說是oi中最為重要的思想方法之一了,往往比起複雜度更優的o(n)演算法有著對問題有更強的應變能力,適用範圍更加廣的優勢。

最直觀的例子比如說求乙個數列在區間[l,r]內的和,我們可以o(n)預處理出字首和並o(1)求解,但是如果加上單點修改,那麼每次o(1)修改後都需要重新o(n)求字首和,複雜度就上去了,而對於區間修改更是僅僅修改的複雜度就達到了o(n)。這時候我們就需要線段樹這種基於分治思想的資料結構來支撐了。(相比較於同樣log級別的樹狀陣列來說,線段樹能解決的問題範圍更加廣泛,也說明了分治的重要意義)。

對於本題的分治策略,我們先考慮解對於區間[l,r]可能出現的情況。

1:最大連續和完全在左區間[l,mid]。

2:最大連續和完全在右區間[mid+1,r]。

3:最大連續和跨越左右區間,由mid向左延伸,由mid+1向右延伸。

接下來是遞迴終點的確定。

顯然,對於單點(區間[l,r](l==r))來說,最大連續和就是這個點代表的數值本身,連續和的起終點都為l(r)。

之後我們就可以直接照著上面的策略寫程式了。

對於本題需要注意一些細節問題,題目對最大連續和子串行做了清晰的定義。

1:和最大。

2:最大和相同時起點盡量靠左。

3:最大和及起點都相同時終點盡量靠左。

且題目要求輸出起終點,這裡我用乙個結構體記錄最大和,起點,終點這三個資訊。

// q.c

#include#include#include#include#includeusing namespace std;

const int m=1000000+10;

struct data ;

data rp=;

for(int i=mid-1;i>=l;lsum+=a[i],i--)

if(lsum+a[i]>=lp.x) lp.x=lsum+a[i],lp.y=i;

for(int i=mid+2;i<=r;rsum+=a[i],i++)

if(rsum+a[i]>rp.x) rp.x=rsum+a[i],rp.z=i;

data res=;

if(lc>res) res=lc;

if(rc>res) res=rc;

return res;

}int main()

求子序列 DP

time limit 1 sec memory limit 128 mb submit 182 solved 8 submit status web board 給定乙個長度為n的數字序列a,從中選取乙個長為m的子串行b滿足 b i b i 1 0 2 i m 求最大的m。第一行輸入乙個整數t,代表...

分而治之 求子序列最大和

這裡只紀錄一下函式的思想 運用遞迴的思想,先後掃瞄左邊最大值,右邊最大值,和跨中點最大值,比較.int max3 int a,int b,int c int divideandconquer int list,int left,int right 下面是 分 的過程 center left righ...

最簡求子序列最大和

已知給定序列a1,a2,a3 an,求a1 an的乙個子串行ai aj,使得ai到aj的和最大 public static int maxsub int sequeuece if sum 0 return max 此演算法時間複雜度為o n 整個演算法只對陣列進行一次掃瞄即可完成操作。從左到右掃瞄過...