好的先把自己的式子推了出來:
樸素:定義\(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-1][j]\)
換成斜率優化的式子:
\(mem[j]-s[j]^2=-s[i]*s[j]+f[i]\)
求\(f[i]\)最大值,所以維護上凸包;斜率\(-s[i]\)單調遞減,所以乙個單調佇列維護凸包。
然後康了一眼別人的題解:維護下凸包?
???黑人問號.jpg
後來發現自己就是個傻子:自己的是對的,只不過斜率那裡和他們的相比少乘了個\(-1\)
\(ou\)。。那就沒事了
(所以我寫的還是自己的)
#include#include#include#define r register int
#define ll long long
using namespace std;
namespace luitaryi const int n=100010;
int n,k,h,t,q[n],pre[210][n];
ll f[n],mem[n],s[n];
inline int x(int i)
inline ll y(int i)
inline double k(int i,int j)
inline void main() {
g(n),g(k); for(r i=1,x;i<=n;++i) g(x),s[i]=s[i-1]+x;
for(r i=1;i<=k;++i) { h=t=0;
for(r j=1;j<=n;++j) {
while(h=-s[j]) ++h;
f[j]=mem[q[h]]+1ll*s[q[h]]*s[j]-1ll*s[q[h]]*s[q[h]];
pre[i][j]=q[h];
while(h2019.08.17
83
P3648 APIO2014 序列分割
part1 首先看到題目,嗯 o o很騷 手玩一波樣例之後發現狀態很好想 這裡簡單地任務階段可以被劃分次數 也就是劃分順序 和劃分位置來劃分 初步想法是 f i j 表示前 i 次最後一次切的是 j 位置 隨後意識到沒法通過上一層進行轉移,這裡出現問題也是正常,因為沒有進行更深入地發掘性質 此處無法...
P3648 APIO2014 序列分割
傳送門 首先容易證明,得分和切的順序沒有關係 所以直接預設先切左邊再切右邊就好了 然後顯然可以 dp 一開始想的是設 f i j 表示切了 i 次,此次把 j 和 j 1 分開,得到的最大價值 那麼顯然列舉上一次切的位置 k 那麼 f i j f i 1 k sum j sum k sum n su...
Luogu 3648 APIO2014 序列分割
題目鏈結 首先要發現乙個重要的性質 分割的順序是不會影響答案的 證明 首先對於沒有交的兩段區間,顯然先後順序改變不會有影響 而對於在同一段區間上的兩次分割 設有一段序列由長度為 x,y,z 的三段拼接起來 如果先分割 xy 和 z 再分割 x 和 y 答案是 x y z x y 而如果先分割 x 和...