標籤:blog os io 資料 for ar div amp
學了模板題之後上網搜下斜率最佳化dp的題目,然後就看到這道題,知道是斜率dp之後有思路就可以自己做不出來,要是不事Crowdsourced Security Testing道的話那就說不定了。
題意:給你n個數,一開始n個數相鄰的數之間是被東西連著的,對於連著的一片的數,它們的價值就是兩兩乘積的和。所以4 5 1 2一開始就是4*5+4*1+4*2+5*1+5*2+1*2... 注意到兩兩乘積的和其實是可以這麼算的((a1+a2+a3+..an)^2-(a1^2+a2^2+....))/2。現在我可以在數與數之間切m刀,問切完之後的最小价值是多少。
一個自然的想法是定義dp[n][t]表示的是前n個數被切了t刀的最小价值,不難發現方程是可以這麼轉移的
dp[i][t]=dp[j][t-1]+((sum[i]-sum[j])*(sum[i]-sum[j])-(d[i]-d[j]))/2 (j<i) 其中d[i]表示前i個數的平方的和
所以這個方程是1個三維的dp,對於1000的資料量是行不通的,所以仿照斜率最佳化的思路,我們可以嘗試寫出當 k<j時,j比k更優的方程,即:
dp[j][t-1]+((sum[i]-sum[j])*(sum[i]-sum[j])-(d[i]-d[j]))/2 < dp[k][t-1]+((sum[i]-sum[k])*(sum[i]-sum[k])-(d[i]-d[k]))/2
經過化簡,我們可以得到一個這樣的東西:
(2dp[j]+sum[j]^2+d[j])-(2dp[k]+sum[k]^2+d[k])/2*(sum[j]-sum[k]) < sum[i]
顯然又是一個斜率式子,利用先前推導的性質我們可以知道,我們每次更新的時候其實就是利用t-1層的資訊推出t層的資訊,推的時候實際有效值也是一個下凸的點集,這個和上一題不一樣之處就在於要更新m次,每次隊列都要重新入隊,但總體來說還是一樣的,由於斜率最佳化后里層的dp達到線性,所以最後複雜度出來是O(n^2)的,仍然要注意之所以一開始可以彈隊首是因為 sum[i]是遞增的。
#pragma warning(disable:4996)#include <iostream>#include <cstdio>#include <vector>#include <algorithm>#include <cstring>#include <string>#include <cmath>using namespace std;#define ll long long#define maxn 1100ll dp[maxn][maxn];ll a[maxn];ll sum[maxn];ll d[maxn];int n, m;ll getup(int i, int j, int t){return (2 * dp[i][t] + sum[i] * sum[i] + d[i]) - (2 * dp[j][t] + sum[j] * sum[j] + d[j]);}ll getdown(int i, int j){return 2 * (sum[i] - sum[j]);}int que[maxn];int qh, qt;int main(){while (cin >> n >> m&&(n||m)){a[0] = d[0] = sum[0] = 0;for (int i = 1; i <= n; ++i){scanf("%I64d", &a[i]);sum[i] = sum[i - 1] + a[i];d[i] = d[i - 1] + a[i] * a[i];}dp[0][0] = 0;for (int i = 1; i <= n; ++i){dp[i][0] = dp[i - 1][0] + a[i] * sum[i - 1];}for (int x = 1; x <= m; ++x){dp[0][x] = 0;qh = qt = 0;que[qt++] = 0;for (int i = 1; i <= n; ++i){while (qh + 1 < qt && getup(que[qh + 1], que[qh], x - 1) <= sum[i] * getdown(que[qh + 1], que[qh])){qh++;}dp[i][x] = dp[que[qh]][x - 1] + ((sum[i] - sum[que[qh]])*(sum[i] - sum[que[qh]]) - (d[i] - d[que[qh]])) / 2;while (qh + 1 < qt && getup(i, que[qt - 1], x - 1)*getdown(que[qt - 1], que[qt - 2]) <= getup(que[qt - 1], que[qt - 2], x - 1)*getdown(i, que[qt - 1])){qt--;}que[qt++] = i;}}printf("%I64d\n", dp[n][m]);}return 0;}