P3648 APIO2014 序列分割

2022-05-19 11:18:57 字數 1397 閱讀 2562

傳送門

首先容易證明,得分和切的順序沒有關係

所以直接預設先切左邊再切右邊就好了

然後顯然可以 $dp$

一開始想的是設 $f[i][j]$ 表示切了 $i$ 次,此次把 $j$ 和 $j+1$ 分開,得到的最大價值

那麼顯然列舉上一次切的位置 $k$ ,那麼 $f[i][j]=f[i-1][k]+(sum[j]-sum[k])(sum[n]-sum[j])$

這個東西是可以斜率優化+滾動陣列,但是很不好寫,一堆邊界問題要想,**就不放了(親自嘗試發現甚至會爆$long\ long$)

另乙個好的思路:設 $f[i][j]$ 表示已經切了 $i$ 次,只考慮前面 $j$ 塊的最大價值

同樣列舉 $k$,$f[i][j]=f[i-1][k]+(sum[i]-sum[j])*sum[j]$

這樣式子就好化了:$f[i][j]=f[i-1][k]+sum[i]sum[j]-sum[j]^2$

:$-sum[i]sum[j]+f[i][j]=f[i-1][k]-sum[j]^2$

那麼 $k=-sum[i],x=sum[j],b=f[i][j],y=f[i-1][k]-sum[j]^2$

發現 $k,x$ 都單調,所以直接斜率優化就好了,同樣要滾動陣列

注意原序列可能有 $0$,那麼 $x$ 就不是單調上公升而是單調不增,求斜率時要注意特判 $x$ 相同的情況!

#include#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long

ll;typedef

long

double

ldb;

inline

intread()

while(ch>='

0'&&ch<='

9')

return x*f;

}const

int n=1e5+7

;int

n,m;

ll sum[n],f[

2][n];

inline ll x(

int x)

inline ll y(

int x)

inline ldb slope(

int i,int

j)int

q[n],l,r;

intmain()

swap(f[

0],f[1

]); }

printf(

"%lld\n

",f[1

][n]);

return0;

}

P3648 APIO2014 序列分割

part1 首先看到題目,嗯 o o很騷 手玩一波樣例之後發現狀態很好想 這裡簡單地任務階段可以被劃分次數 也就是劃分順序 和劃分位置來劃分 初步想法是 f i j 表示前 i 次最後一次切的是 j 位置 隨後意識到沒法通過上一層進行轉移,這裡出現問題也是正常,因為沒有進行更深入地發掘性質 此處無法...

P3648 APIO2014 序列分割 斜率優化

好的先把自己的式子推了出來 樸素 定義 f i j 表示前 i 個數進行 j 次切割的最大得分,s i 為字首和 那麼轉移方程為 f i j max f i 1 j s j s i s j 優化一下 省掉第一維 f i max mem j s j s i s j f j mem j 相當於 f i ...

Luogu 3648 APIO2014 序列分割

題目鏈結 首先要發現乙個重要的性質 分割的順序是不會影響答案的 證明 首先對於沒有交的兩段區間,顯然先後順序改變不會有影響 而對於在同一段區間上的兩次分割 設有一段序列由長度為 x,y,z 的三段拼接起來 如果先分割 xy 和 z 再分割 x 和 y 答案是 x y z x y 而如果先分割 x 和...