您的位置:首页 > 其它

BZOJ 1010 斜率DP

2017-02-16 16:22 302 查看
先写出dp方程:

dp[i]=min(dp[j]+(sum[i]-sum[j]+i-j-1-L)^2) (j小于i)

令f[i]=sum[i]+i,c=1+l

则dp[i]=min(dp[j]+(f[i]-f[j]-c)^2)

化简之后发现方程形如:

f[i]=Min(a[i]∗b[j]+c[j]+d[i])

想到用斜率优化

决策单调性证明和斜率表达式

已知x(j,k)小于f(i)时k决策更优,

又因为f【i】是递增的,把斜率维护一个下凸,然后就都是套路了,参考上一题hdu3407.(斜率方程出来后就基本一样了)

然后就是要注意这里没有直接用up/down去和f【i】直接比大小,而是用up和down*f【i】这样去比较,所以要注意down的正负号问题,不然就反了。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <deque>
using namespace std;
typedef long long LL;

const int maxn=50005;

int L,R,n;
LL s[maxn],C;
int q[maxn];
LL dp[maxn];
LL getDP(int i,int j){
return dp[j]+(s[i]-s[j]-C)*(s[i]-s[j]-C);
}
LL UP(int k,int j){
return dp[j]-dp[k]+(s[j]+C)*(s[j]+C)-(s[k]+C)*(s[k]+C);
}
LL DOWN(int k,int j){
return 2*(s[j]-s[k]);
}

int main(){
scanf("%d%lld",&n,&C);
C++;
for(int i=1;i<=n;i++){
LL t;
scanf("%lld",&t);
s[i]=s[i-1]+t;
}
for(int i=1;i<=n;i++){
s[i]+=i;
}
L=R=0;
dp[0]=0;
q[0]=0;
for(int i=1;i<=n;i++){
while(L<R&&UP(q[L],q[L+1])<=s[i]*DOWN(q[L],q[L+1])){
L++;
}
dp[i]=getDP(i,q[L]);
while(L<R&&UP(q[R-1],q[R])*DOWN(q[R],i)>UP(q[R],i)*DOWN(q[R-1],q[R])){
R--;
}
q[++R]=i;
}
printf("%lld\n",dp
);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: