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
第一行輸入兩個整數N,L.接下來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;
}