洛谷 P1121 環狀最大兩段子段和 解題報告

2022-04-30 06:33:06 字數 1573 閱讀 7370

給出一段環狀序列,即認為\(a_1\)和\(a_n\)是相鄰的,選出其中連續不重疊且非空的兩段使得這兩段和最大。

輸入輸出格式

輸入格式:

第一行是乙個正整數\(n(n≤2×10^5)\) ,表示了序列的長度。

第二行包含\(n\)個絕對值不大於10000的整數\(a_i\),描述了這段序列,第乙個數和第\(n\)個數是相鄰的。

輸出格式:

乙個整數,為最大的兩段子段和是多少。

最開始想的倍增優化,感覺其實好像也可以做,但寫起來複雜到毀天滅地。

於是聽教練講了\(o(n)\)的做法。

先考慮單鏈情況。

對於這個序列,我們首先劃分它的狀態

其中\(s1\)區和\(s3\)區是選中的兩段。

不妨就把這些劃分為\(dp\)的狀態。

令\(dp[i][j]\)代表在長度\(i\)時處於\(j\)區的最大答案

狀態轉移:

\(dp[i][0]=max(dp[i-1][0],dp[i-1][3]);\)

\(dp[i][1]=max(dp[i-1][4],dp[i-1][1])+a[i];\)

\(dp[i][2]=max(dp[i-1][1],dp[i-1][2]);\)

\(dp[i][3]=max(max(dp[i-1][2],dp[i-1][1]),dp[i-1][3])+a[i];\)

\(dp[i][4]=dp[i-1][4];\)

容易發現,\(dp[i][4]\)總是0,遂可以扔掉這一維。

解決了單鏈的,我們想一想如果推廣到環上。一般的方法是延長鏈為兩倍,但這個並不是區間\(dp\),所以很難限定區間。

這裡提供一種類似於費用提前的做法。

還是這張圖,假設選取了\(s0,s2,s4\)三段

不就是把環連起來了嗎

於是問題就轉化到了找最小兩段子段和上,做法是一樣的。

不過需要注意的是,最小子段和不能兩端同時取到端點,否則就是單段最大子段和了。

code:

#include #include int min(int x,int y) 

const int n=200010;

const int inf=0x3f3f3f3f;

int a[n],dp[n][4],n,ans=-inf,sum=0;//0不選右,1左段,2中間不選,3右段

void dp1()

ans=max(dp[n][0],dp[n][3]);

}void dp2()

ans=max(ans,sum-dp[n][0]);

}int main()

dp1();

dp2();

printf("%d\n",ans);

return 0;

}

2018.6.6

洛谷 P1121 環狀最大兩段子段和

題目描述 給出一段環狀序列,即認為a 1 和a n 是相鄰的,選出其中連續不重疊且非空的兩段使得這兩段和最大。輸入輸出格式 輸入格式 輸入檔案maxsum2.in的第一行是乙個正整數n,表示了序列的長度。第2行包含n個絕對值不大於10000的整數a i 描述了這段序列,第乙個數和第n個數是相鄰的。輸...

P1121 環狀最大兩段子段和

p1121 環狀最大兩段子段和 給出一段環狀序列,選出其中連續不重疊且非空的兩段使得這兩段和最大。n 2e5 輸入樣例 1 複製 7 2 4 3 1 2 4 3 輸出樣例 1 複製 9 題解 一道好題 考慮兩種情況,o代表選擇 ooo ooo 正做一遍最大子段和,倒做一遍最大子段和兩者相加 ooo ...

P1121 環狀最大兩段子段和 DP

p1121 環狀最大兩段子段和 難度提高 省選 題目描述 給出一段環狀序列,即認為a 1 和a n 是相鄰的,選出其中連續不重疊且非空的兩段使得這兩段和最大。輸入輸出格式 輸入格式 輸入檔案maxsum2.in的第一行是乙個正整數n,表示了序列的長度。第2行包含n個絕對值不大於10000的整數a i...