APIO2014 序列分割

2022-05-26 20:48:10 字數 3056 閱讀 3171

題目鏈結

你正在玩乙個關於長度為 n 的非負整數序列的遊戲。這個遊戲中你需要把序列分成 k + 1 個非空的塊。為了得到 k + 1塊,你需要重複下面的操作 k 次:

選擇乙個有超過乙個元素的塊(初始時你只有一塊,即整個序列)

選擇兩個相鄰元素把這個塊從中間分開,得到兩個非空的塊。

每次操作後你將獲得那兩個新產生的塊的元素和的乘積的分數。你想要最大化最後的總得分。

輸入格式:

第一行包含兩個整數 \(n\) 和 \(k\)。保證 \(k + 1 \leq n\)。

第二行包含 \(n\) 個非負整數 \(a_1, a_2, \cdots, a_n (0 \leq a_i \leq 10^4)\),表示前文所述的序列。

輸出格式:

第一行輸出你能獲得的最大總得分。

第二行輸出 \(k\) 個介於 \(1\) 到 \(n - 1\) 之間的整數,表示為了使得總得分最大,你每次操作中分開兩個塊的位置。第 \(i\) 個整數 \(s_i\) 表示第 \(i\) 次操作將在 \(s_i\) 和 $s_ $之間把塊分開。

如果有多種方案使得總得分最大,輸出任意一種方案即可。

輸入樣例#1:

7 3

4 1 3 4 0 2 3

輸出樣例#1:
108

1 3 5

你可以通過下面這些操作獲得 \(108\) 分:

初始時你有一塊 \((4, 1, 3, 4, 0, 2, 3)\)。在第 \(1\) 個元素後面分開,獲得 \(4 \times (1 + 3 + 4 + 0 + 2 + 3) = 52\) 分。

你現在有兩塊 \((4), (1, 3, 4, 0, 2, 3)\)。在第 \(3\) 個元素後面分開,獲得 \((1 + 3) \times (4 + 0 + 2 + 3) = 36\) 分。

你現在有三塊 \((4), (1, 3), (4, 0, 2, 3)\)。在第 \(5\) 個元素後面分開,獲得 \((4 + 0) \times (2 + 3) = 20\) 分。

所以,經過這些操作後你可以獲得四塊 \((4), (1, 3), (4, 0), (2, 3)\) 並獲得 \(52 + 36 + 20 = 108\) 分。

限制與約定

第乙個子任務共 \(11\) 分,滿足 \(1 \leq k < n \leq 10\)。

第二個子任務共 \(11\) 分,滿足 \(1 \leq k < n \leq 50\)。

第三個子任務共 \(11\) 分,滿足 \(1 \leq k < n \leq 200\)。

第四個子任務共 \(17\) 分,滿足 \(2 \leq n \leq 1000, 1 \leq k \leq \min\\)。

第五個子任務共 \(21\) 分,滿足 \(2 \leq n \leq 10000, 1 \leq k \leq \min\\)。

第六個子任務共 \(29\) 分,滿足 \(2 \leq n \leq 100000, 1 \leq k \leq \min\\)。

在解決這個問題之前,我們先大膽口胡乙個結論:分割的順序不影響最後的結果。

接下來就是這個結論的證明了:

設兩次分割把佇列分為了a,b,c三個部分。

先分割a,b之間,再分割b,c之間:\(ans=a*(b+c)+b*c=a*b+a*c+b*c\)

先分割b,c之間,再分割a,b之間:\(ans=c*(a+b)+a*b=a*b+a*c+b*c\)

由此可以得出分割的順序不影響最後的結果。

接下來我們就可以進行dp了。

這是乙個很明顯的二維dp。

\(dp[i][k]\)表示前\(i\)個數被分割了\(k\)次所能得到的最大的答案。

轉移方程為\(dp[i][k]=max(dp[j][k-1]+\sum_^a[u]*\sum_^a[u])\)(在第\(k\)個數和第\(k+1\)個數之間分割)

證明:假設\(dp[j][k-1]\)最右邊的分割點為\(o\)和\(o+1\)(從\(j\)轉移後\(dp[i][k]\)最後),

則\(dp[i][k-1]=dp[j][k-1]+\sum_^a[u]*\sum_^a[u]\)

所以\(dp[i][k]=dp[i][k-1]+\sum_^a[u]*\sum_^a[u]\)

\(=dp[j][k-1]+\sum_^a[u]*\sum_^a[u]+\sum_^a[u]*\sum_^a[u]\)

\(=dp[j][k-1]+\sum_^a[u]*\sum_^a[u]\)

接下來我們用字首和減小時間複雜度,

設\(sum[i]=\sum_^a[j]\)

所以\(dp[i][k]=max(dp[j][k-1]+sum[j]*(sum[i]-sum[j]))\)

這個轉移方程時間複雜度為o(n^2),因為\(2 \leq n \leq 100000\)所以我們用斜率優化。

重點:

我們取\(j\),\(p\)滿足 \(p且\(j\)比\(k\)更優,那麼有如下不等式:

\[dp[j][k-1]+sum[j]*(sum[i]-sum[j])>dp[p][k-1]+sum[p]*(sum[i]-sum[p])

\]化簡後得:

\[\frac\leq sum[i]

\]接下來維護乙個下凸殼就可以了。

注意:題目中\(a[i]\)的範圍是非負整數,所以\(a[i]\)可以為0,計算時需要特判。

上**:

#include#define inf 1e18

using namespace std;

int n,k;

long long a[100009],s[100009];

long long dp[100009];

long long pp[1000009],g[100009];

long long l=1,r=1;

double js(int j,int k)

int main()

for(int j=1;j<=n;j++)

g[j]=dp[j];

}printf("%lld",dp[n]);

return 0;

}

APIO 2014 序列分割

題目鏈結 演算法 首先 我們發現將一段序列切成若干段所獲得的收益與順序無關 於是我們可以用fi,j表示切i次 前j個數的最大收益 令sumi表示ai的字首和 顯然 fi,j max 斜率優化即可 此題記憶體限制較緊 可以使用滾動陣列優化空間複雜度 時間複雜度 o nk includeusing na...

APIO2014 序列分割

將乙個長度為 n 的序列分成 k 段,每次分割一段長度 ge 2 的序列,得分為兩邊序列元素和的乘積,求最大得分 2 leq n leq100000,1 leq k leq min 0 a i 10 4 我們發現一對元素 i,j 產生貢獻 a i a j 的條件是分割後元素不在同一段裡 於是我們知道...

APIO2014 序列分割

嘟嘟嘟 複習一下斜率優化,感覺已經忘得差不多了 這題切入點在與答案跟切的順序無關。證明就是假如有三段權值分別為 x,y,z 那麼這兩刀不管按什麼順序切,得到的結果都是 xy xz yz 然後就可以dp。令 dp i j 表示前 i 個數切 j 刀的最大得分,於是就有 dp i j max 觀察這個式...