[BZOJ] 1010 [HNOI2008]玩具裝箱toy

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 12664  Solved: 5539
[Submit][Status][Discuss]
Description
  P教授要去看奧運,但是他舍不下他的玩具,於是他決定把所有的玩具運到北京。他使用自己的壓縮器進行壓
縮,其可以將任意物品變成一堆,再放到一種特殊的一維容器中。P教授有編號爲1...N的N件玩具,第i件玩具經過
壓縮後變成一維長度爲Ci.爲了方便整理,P教授要求在一個一維容器中的玩具編號是連續的。同時如果一個一維容
器中有多個玩具,那麼兩件玩具之間要加入一個單位長度的填充物,形式地說如果將第i件玩具到第j個玩具放到一
個容器中,那麼容器的長度將爲 x=j-i+Sigma(Ck) i<=K<=j 製作容器的費用與容器的長度有關,根據教授研究,
如果容器長度爲x,其製作費用爲(X-L)^2.其中L是一個常量。P教授不關心容器的數目,他可以製作出任意長度的容
器,甚至超過L。但他希望費用最小.

Input
  第一行輸入兩個整數NL.接下來N行輸入Ci.1<=N<=50000,1<=L,Ci<=10^7

Output
  輸出最小費用

Sample Input
5 4

3

4

2

1

4
Sample Output
1
HINT
Source

[Submit][Status][Discuss]

斜率優化第一題,感覺很玄妙。
dp(i)=min(dp(i)+(sum(i)-sum(j)+i-j-1-L)^2)
設a(i)=sum(i)+i,b(i)=sum(i)+i+1+L
可見a,b均單增
接着原式可以化爲
dp(i)= dp(j)+(a(i)-b(j))^2
2a(i)b(j)+dp(i)-a(i)^2=dp(j)+b(j)^2
設X=b(j),Y=dp(j)+b(j)^2
Y=2a(i)X+dp(i)-a(i)^2
這是一條斜率爲2a(i),截距爲dp(i)-a(i)^2的直線
對於一個i,a(i)是定值,要最小化dp(i),就要最小化截距

這個直線過點(b(j),dp(j)+b(j)^2),也就是剛纔代換的X和Y
b(j)單增,所以這些點橫座標單增,可以用單調隊列維護一個凸包

一個點P是最優解當且僅當slope(P,P+1)>=2a(i),這時候就可以與直線相切了。

維護的時候,在隊首刪掉斜率小於2a(i)的點,因爲隨着a(i)單增,這些點一定不可能成爲最優了
在隊尾刪掉斜率大於slope(Pi,Ptail)的點,否則就夠不成凸包了。

有幾個不理解的地方,爲什麼公式裏的min可以去掉?這樣推導的動力是什麼?

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;

const int MAXN=500005;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

int n,L;
int dp[MAXN],sum[MAXN];

inline double a(int x){return sum[x]+x;}
inline double b(int x){return sum[x]+x+1+L;}
inline double X(int x){return b(x);}
inline double Y(int x){return dp[x]+b(x)*b(x);}
inline double slope(int x,int y){return 1.0*(Y(y)-Y(x))/(X(y)-X(x));}

int Q[MAXN],head=1,tail=1;

signed main(){
    n=rd();L=rd();
    for(int i=1;i<=n;i++){
        int x=rd();
        sum[i]=sum[i-1]+x;
    }
    for(int i=1;i<=n;i++){
        while(head<tail&&slope(Q[head],Q[head+1])<2*a(i)) head++;
        dp[i]=dp[Q[head]]+(a(i)-b(Q[head]))*(a(i)-b(Q[head]));
        while(head<tail&&slope(i,Q[tail-1])<slope(Q[tail-1],Q[tail])) tail--;
        Q[++tail]=i;
    }
    cout<<dp[n]<<endl;
    return 0;
}
發佈了180 篇原創文章 · 獲贊 6 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章