征途题解
征途题解
恶心题。我太弱了
回到正题,
将每个式子拆开:
合起来,运用乘法分配律,即为:
后面一项为常数,为路程总和,
便设
暴力DP方程为:
拆平方项,移项:
维护一个单调的下凸壳即可,可以用循环队列节省空间。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=3006;
int n,m,t,head,tail,o=0,sum[N],f[2][N];
struct point{int x,y;}tmp,q[N];
inline int read(){
int T=0,F=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
return F*T;
}
bool check(point u,point v,int z){return v.y-u.y<=2*sum[z]*(v.x-u.x);}
bool check2(point u,point v,point z){return (v.y-u.y)*(z.x-v.x)>=(z.y-v.y)*(v.x-u.x);}
int main(){
n=read(),m=read(),f[0][0]=0;
for(int i=1;i<=n;++i) t=read(),sum[i]=sum[i-1]+t,f[o][i]=sum[i]*sum[i];
for(int j=2;j<=m;++j){
o^=1,q[1].x=0,q[1].y=0,head=tail=1;
for(int i=1;i<=n;++i){
while(head<tail&&check(q[head],q[head+1],i)) ++head;
f[o][i]=q[head].y-2*sum[i]*q[head].x+sum[i]*sum[i],tmp.x=sum[i],tmp.y=f[o^1][i]+sum[i]*sum[i];
while(head<tail&&check2(q[tail-1],q[tail],tmp)) --tail;
q[++tail]=tmp;
}
}
t=f[o][n]*m-sum[n]*sum[n];
printf("%d\n",t);
return 0;
}