APIO2014 序列分割

2022-05-09 10:42:20 字數 1526 閱讀 3316

嘟嘟嘟

複習一下斜率優化,感覺已經忘得差不多了……

這題切入點在與答案跟切的順序無關

證明就是假如有三段權值分別為\(x, y, z\),那麼這兩刀不管按什麼順序切,得到的結果都是\(xy + xz + yz\)。

然後就可以dp。

令\(dp[i][j]\)表示前\(i\)個數切\(j\)刀的最大得分,於是就有\(dp[i][j] = max\\)。

觀察這個式子,發現\(j\)只能從\(j - 1\)轉移過來,那索性把\(j\)換到第一維,然後就可以滾動陣列省去第一維了,即\(f[i] = max \\)。

看到乘積,似乎能想到斜率優化。於是假設\(t_2 > t_1\),且\(t_2\)的決策比\(t_1\)優,這時候\(t_1\)就可以扔掉了。那麼就有

\[\begin

g[t_2] + s[t_2] * (s[i] - s[t_2]) &\geqslant g[t_1] + s[t_1] * (s[i] - s[t_1]) \\

\frac &\leqslant s[i]

\end\]

於是我們用單調佇列維護乙個下凸殼就好啦。

坑點在於\(s[t_1] = s[t_2]\),這時候斜率直接返回\(-inf\),把\(t_1\)扔出去。

彩蛋:某谷第12個點卡精度,然後我發現乘以\(1.0\)比強制型別轉換成double精度要高……

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

#define enter puts("")

#define space putchar(' ')

#define mem(a, x) memset(a, x, sizeof(a))

#define in inline

typedef long long ll;

typedef double db;

const ll inf = 1e18;

const db eps = 1e-8;

const int maxn = 2e5 + 5;

const int maxm = 205;

inline ll read()

inline void write(ll x)

int n, k;

ll a[maxn];

ll sum[maxn], f[maxn], g[maxn];

int q[maxn], pre[maxn][maxm];

in db slope(int i, int j)

int main()

memcpy(g, f, sizeof(f));

}write(f[n]), enter;

for(int j = n, i = k; i; --i) j = pre[j][i], write(j), space; enter;

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 序列分割

題目鏈結 你正在玩乙個關於長度為 n 的非負整數序列的遊戲。這個遊戲中你需要把序列分成 k 1 個非空的塊。為了得到 k 1塊,你需要重複下面的操作 k 次 選擇乙個有超過乙個元素的塊 初始時你只有一塊,即整個序列 選擇兩個相鄰元素把這個塊從中間分開,得到兩個非空的塊。每次操作後你將獲得那兩個新產生...