BZOJ3675 Apio2014 序列分割

2022-05-03 16:36:10 字數 1253 閱讀 4694

傳送門​  之前我也遇到過一次這種「兩段之和乘積作為貢獻「的問題:考慮把這一種\((\sum) *(\sum)\)的形式拆括號,就可以發現貢獻其實就是分別處於左右的兩兩元素乘積之和。

​  題目的分割\(k\)次,其實就是要你把序列分成\(k+1\)段。

​  再考慮在題目中如此的分割方法下,貢獻是怎麼產生的。對於每乙個元素\(a_i\),每次分割時,若涉及到自己,則會貢獻一定的乘積\(a_i(\sum)\)。細心想一想就會發現,這個\(\sum\)的總值就是在最終方案下不處於\(a_i\)所在段的元素之和。

單向考慮每一項乘積,(這裡有點跳)總的來算,每一段\([l,r]\)的貢獻就是\((\sum_^ra_i)(\sum_^a_i)\)。記\(a\)的字首和為\(s\),則貢獻是\((s_r-s_)s_\).

我們可以寫出dp式,\(f_\)表示前\(i\)個數恰好分成\(j\)段的貢獻最大值:

\[f_=\max\+(s_i-s_k)s_k\}\;\;(k

直接dp是\(\mathcal o((k+1)n^2)\)的。而看到這個式子比較簡單,考慮斜率優化。這裡省去第二維,整體做\(k+1\)次即可。

​  設\(k,\(j\)比\(k\)優,則有:

\[\begin

f_j+(s_i-s_j)s_j&>f_+(s_i-s_k)s_k\\

f_j+s_is_j-s_j^2&>f_k+s_is_k-s_k^2\\

s_i(s_j-s_k)&>(s_j^2-f_j)-(s_k^2-f_k)\\

\frac&

直接做就可以了。

#include #include using namespace std;

typedef long long ll;

const int n=100005;

const ll inf=1ll<<62;

const double eps=1e-6;

int n,m,a[n];

int q[n],head,tail;

ll s[n],real_f[n],real_g[n],*f=real_f,*g=real_g;

inline double slope(int a,int b)

int main()

n=cnt; m=min(m,n-1)+1;

for(int j=2;j<=m;j++)

swap(f,g);

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

return 0;

}

bzoj3675 APIO2014 序列分割

time limit 40 sec memory limit 128 mb submit 1468 solved 607 submit status discuss 小h最近迷上了乙個分隔序列的遊戲。在這個遊戲裡,小h需要將乙個長度為n的非負整數序列分割成k 1個非空的子串行。為了得到k 1個子序列...

BZOJ3675 Apio2014 序列分割

portal 根據乘法分配律,其實最後答案就是分割後,對每個塊的和,兩兩求乘積加和。那麼割的順序就沒有影響了。遞推式可以寫成 f i k mi n f j k 1 sum i sum j sum j 那麼對於k j且決策k優於決策j f k l 1 sum i sum k sum k f j l 1...

BZOJ 3675 Apio2014 序列分割

bzoj 3675 apio2014 序列分割 小h最近迷上了乙個分隔序列的遊戲。在這個遊戲裡,小h需要將乙個長度為n的非負整數序列分割成k 1個非空的子串行。為了得到k 1個子序列,小h需要重複k次以下的步驟 1.小h首先選擇乙個長度超過1的序列 一開始小h只有乙個長度為n的序列 也就是一開始得到...