(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
题目:传送门
题目描述及样例在最下面。
思路:
考虑斜率优化,决策单调性。
ar[i]为(前缀i的长度和+i)
f[i]为到i所花费的钱
f[i]=min(f[j-1]+(ar[i]-ar[j-1]-L-1)^2);
=> f[i]=min(f[j]+(ar[i]-ar[j]-L-1)^2);
令c=L+1
第一步:
假设j < k < i,如果点 i 在点 k 的决策优于在点 j 的决策,即
f[k] + (ar[i]-ar[k]-c)^2 <= f[j] + (ar[i]-ar[j]-c)^2
=> f[k] - 2*ar[i]* (ar[k]+c) + (ar[k]+c)^2 <= f[j] - 2*ar[i]* (ar[j]+c) + (ar[j]+c)^2
=> f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2 <= 2*ar[i]* (ar[k]-ar[j])
=> (f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2)/2* (ar[k]-ar[j]) <= ar[i]
将上述式子定义为j和k的斜率。注意:j < k。
如果在点 k 处决策优于在点 j 处决策,则有:斜率(j, k) <= ar[i]
(f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2)/2* (ar[k]-ar[j]) <= ar[i]
第二步:
使用单调队列来维护这一关系。使得队列中的斜率单调上升。
head为队首,tail为队尾。新加入的点为i。
斜率(head,head+1) <= ar[i],则将head点pop出去。
因为head+1点除的决策优于head点。
如果斜率(tail, i) < 斜率(tail-1,tail),则将tail点pop出去。
如果不pop出去,无法维持队列中元素的决策单调性(单调上升)。
AC代码:
#include<bits/stdc++.h>
#define fang(a) (a)*(a)
using namespace std;
typedef long long LL;
const int N = 50000+5;
int n,k,head,tail;
int stak[N];
LL ar[N],f[N];
/*
f[k] + (ar[i]-ar[k]-c)^2 <= f[j] + (ar[i]-ar[j]-c)^2
=> f[k] - 2*ar[i]*(ar[k]+c) + (ar[k]+c)^2 <= f[j] - 2*ar[i]*(ar[j]+c) + (ar[j]+c)^2
=> f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2 <= 2*ar[i]*(ar[k]-ar[j])
=> (f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2)/2*(ar[k]-ar[j]) <= ar[i]
*/
double fx(int x,int y){
return (f[y]-f[x]+fang(ar[y]+k+1)-fang(ar[x]+k+1))/(2*(ar[y]-ar[x]));
}
int main(){
while(~scanf("%d%d",&n,&k)){
ar[0]=0;head=tail=1;
memset(stak,0,sizeof(stak));
memset(f,0,sizeof(f));
for(int i=1,x;i<=n;++i){
scanf("%d",&x);
ar[i]=ar[i-1]+x;
}
for(int i=1;i<=n;++i)ar[i]+=i;
for(int i=1;i<=n;++i){
while(head<tail&&fx(stak[head],stak[head+1])<=ar[i])head++;
f[i]=f[stak[head]]+fang(ar[i]-ar[stak[head]]-k-1);
while(head<tail&&fx(stak[tail-1],stak[tail])>fx(stak[tail],i))tail--;
stak[++tail]=i;
}
printf("%lld\n",f[n] );
}
return 0;
}
BZOJ1010: 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