题目描述
题解
题目描述认真读
转移方程:
f(i)=min{f(j)+(i−j−1+si−sj−L)2}
刚开始上来就化然后发现不可做。
考虑换元 令
pi=si+i,L′=L+1
则
f(i)=min{f(j)+(pi−pj−L)2}
然后展开
f(i)=min{−2pj∗pi+f(j)+p2j+2pjL}+p2i+L2−2piL
k=−2pj,b=f(j)+p2j+2pjL
明显可以用斜率优化。
这道题启示我们:一定要把ij相关的放在一起!
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
const int max_n=5e4+5;
LL n,L,x;
LL s[max_n],p[max_n];
LL q[max_n],head,tail;
LL f[max_n];
inline LL K(LL j){return -2*p[j];}
inline LL B(LL j){return f[j]+p[j]*p[j]+2*L*p[j];}
inline LL Y(LL i,LL j){return K(j)*p[i]+B(j);}
inline bool cmp(LL x1,LL x2,LL x3){
LL w1=(K(x1)-K(x3))*(B(x2)-B(x1));
LL w2=(K(x1)-K(x2))*(B(x3)-B(x1));
return w1>=w2;
}
int main(){
scanf("%lld%lld",&n,&L);
for (LL i=1;i<=n;++i) scanf("%lld",&x),s[i]=s[i-1]+x,p[i]=s[i]+i; L++;
head=tail=0;
for (LL i=1;i<=n;++i){
while (head<tail&&Y(i,q[head])>=Y(i,q[head+1])) head++;
f[i]=Y(i,q[head])+p[i]*p[i]-2*L*p[i]+L*L;
while (head<tail&&cmp(i,q[tail-1],q[tail])) tail--;
q[++tail]=i;
}
printf("%lld\n",f[n]);
}
总结
强转注意中间爆int