bzoj3675: [Apio2014]序列分割

bzoj3675: [Apio2014]序列分割

Description

小H最近迷上了一個分割序列的遊戲。在這個遊戲裏,小H需要將一個長
度爲N的非負整數序列分割成k+l個非空的子序列。爲了得到k+l個子序列,
小H將重複進行七次以下的步驟:
1.小H首先選擇一個長度超過1的序列(一開始小H只有一個長度爲n的
序列一一也就是一開始得到的整個序列);
2.選擇一個位置,並通過這個位置將這個序列分割成連續的兩個非空的新
序列。
每次進行上述步驟之後,小H將會得到一定的分數。這個分數爲兩個新序
列中元素和的乘積。小H希望選擇一種最佳的分割方案,使得k輪(次)之後,
小H的總得分最大。

Input

輸入文件的第一行包含兩個整數n和尼(k+1≤n)。
第二行包含n個非負整數a1,n2….,an(0≤ai≤10^4),表示一開始小H得
到的序列。

Output

一行包含一個整數,爲小H可以得到的最大得分。

Sample Input

7 3

4 1 3 4 0 2 3

Sample Output

108

HINT

【樣例說明】

在樣例中,小H可以通過如下3輪操作得到108分:

1.-開始小H有一個序列(4,1,3,4,0,2,3)。小H選擇在第1個數之後的位置

將序列分成兩部分,並得到4×(1+3+4+0+2+3)=52分。

2.這一輪開始時小H有兩個序列:(4),(1,3,4,0,2,3)。小H選擇在第3個數

字之後的位置將第二個序列分成兩部分,並得到(1+3)×(4+0+2+

3)=36分。

3.這一輪開始時小H有三個序列:(4),(1,3),(4,0,2,3)。小H選擇在第5個

數字之後的位置將第三個序列分成兩部分,並得到(4+0)×(2+3)=

20分。

經過上述三輪操作,小H將會得到四個子序列:(4),(1,3),(4,0),(2,3)並總共得到52+36+20=108分。

【數據規模與評分】

:數據滿足2≤n≤100000,1≤k≤min(n -1,200)。

題目大意:

給定n個數,將這n個數劃分爲k+1個區間,使得每2個區間的和的乘積的總和儘可能大

分析:

解法1:

容易得知,劃分區間的順序對答案是沒有影響的,證明如下:
不妨將原始序列分爲3段,a,b,c分別表示3段區間的元素和
我們如果先從a,b間分割,再從b,c間分割,那麼價值爲a(b+c)+bc=ab+ac+bc
如果先從b,c間分割,再從a,b間分割,那麼價值爲(a+b)c+ab=ab+ac+bc
這兩種方法得到的價值相等,也就說明劃分區間的先後順序不影響答案

那麼本題就可以套用劃分dp的模型了

記f[i,k]爲前i個數通過劃分區間得到的最大分數
s[i]爲原始序列中第i個數到第n個數的後綴和
那麼
f[i,k]=max{f[j,k-1]+(s[j+1]-s[i+1])s[i+1]}
然後通過對方程式進行變形(打公式好麻煩啊,這裏就不再贅述了QAQ),最終可以得到

假設有2個決策 a,b,如果
公式
那麼決策b會比決策a優

然後就沒有然後了 經典的斜率優化 時間複雜度O(n*k) 空間複雜度可以用滾動數組優化到O(n)

解法2:

這個解法是本蒟蒻在網上通過多方查找,最後再加上本人稍稍yy得到的,如有不正確之處,還望各位大神指正
爲了方便,我們將本題轉化爲:給定一個含n個數的序列,將這個序列劃分爲k段,使得每一段的平方和的總和最小
記s[i]表示前i個數的前綴和
那麼我們可以得出這樣一個方程
f[i,k]=min{f[j,k-1]+(s[i]-s[j])^2} (方程1)
這個方程受到了狀態k的限制,因此這個方程的複雜度爲O(nk),狀態k也是解法1的時間複雜度不能低於O(nk)的根本原因。(其實解法2也可以將解法1的方程搬過來優化,只不過爲了方便,我們在這裏將方程寫成另一種形式)

現在,我們仔細觀察下上面的方程,通過上面的方程,我們可以聯想到:
f[i]=min{f[j]+(s[i]-s[j])^2}+c (方程2)
這個是斜率優化的非常經典的方程,也可以說是一個模板方程
這個方程對應的也是一個區間劃分問題,在這個問題中,最後可能將原始區間劃分爲1段,2段,3段,或者是n段……
而究竟劃分成多少段,正是由這個c決定的。
當c由小到大取遍[0,inf)中的每一個數時,區間劃分的段數也由大到小取遍n至1中的每一個值。(這個性質非常關鍵,正是本題的核心所在)

而在本題中,我們沒有c這個東東,我們有的只是”必須劃分成k+1段”的限定。
而這個劃分k+1段的方案,也必定對應於一個特殊的c,這個c使得方程f[i]=min{f[j]+(s[i]-s[j])^2}+c能將原始序列劃分爲k+1段。

因此,我們可以二分c。每一個c都對應於一個段數,當c十分接近inf時,段數肯定就爲1;當c=0時,段數就爲n。
我們在二分c的時候,同時用dp檢查一下段數是多少(O(n)的時間),如果段數正好爲k+1,那麼我們的方程2得到的結果,也就是方程1dp的最終結果再加上c(k+1)。
我們將此時的f[n]減去c(k+1),即可得到平方和的最小值minsum。
我們再將所有數的和的平方(s[n]^2),減去minsum,再將這個結果除以2,最終得到的就是本題的答案。
時間複雜度O(log(inf)*n)

因此,本題的k也就可以繼續加強到100000以上的數量級

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章