APIO2014 序列分割

2022-08-20 23:12:13 字數 1116 閱讀 3631

here

這題竟然卡常 \(+\) 卡精度,我 \(……\)

令 \(f[i][k]\) 表示前 \(i\) 個元素分了 \(k\) 次的最大值,我們可以得出轉移方程(\(sum\)為字首和陣列):

\[f[i][k] = max\

\]這乙個轉移樸素來算是 \(o(n^2k)\) 的複雜度,我們不妨把式子拆開:

\[f[i][k] = f[j][k-1] + sum[j] * (sum[i] - sum[j])\\

= f[j][k-1] + sum[i]*sum[j] - sum[j] ^ 2\\

f[i][k] - sum[i] * sum[j] = f[j][k-1] - sum[j]^2\]

將 \(f[i][k]\) 看作 \(y\) 上截距, \(sum[j]\) 看作自變數, \(f[j][k-1] - sum[j]^2\) 看作因變數,\(-sum[i]\) 則為斜率,由於\(-sum[i]\) 單調遞減,我們可以考慮斜率優化,維護乙個上凸包,複雜度為 \(o(nk)\),空間的話,\(f\) 陣列可以滾動,但是我太懶了,所以沒滾\(……\)

由於卡常,我開了 \(o2\) (我太菜了)

有一點要注意的就是計算斜率的時候分母有可能為 \(0\),我們特判一下

#includeusing namespace std;

typedef long long ll;

typedef long double d;

const int n = 100010;

const int k = 220;

ll f[n][k], a[n], sum[n], q[n], road[n][k], n, kmax;

d x(int j)

d y(int j, int k)

d slope(int i, int j, int k)

void print(int i, int k)

int main()

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

print(n, kmax);

return 0;

}

注意精度??

注意分母為 \(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 觀察這個式...