bzoj4518: [Sdoi2016]征途
第一眼看到这题的想法:这不就是一题傻逼DP吗。。。水经验
然而……诶诶诶DP怎么写
%了题解(还被嘲讽%题解比自己AC还多)原来是式子化简错了(囧orz,所以我不化简给你),菜啊。
然后写个斜率优化就行(懒得滚)。。记得开LL(搞得都不知道什么时候开了)
/* k1<k2 且 k2优于k1 f[k1][j-1]+(s[i]-s[k1])*(s[i]-s[k1]) >= f[k2][j-1]+(s[i]-s[k2])*(s[i]-s[k2]) f[k1][j-1]-2*s[i]*s[k1]+s[k1]^2 >= f[k2][j-1]-2*s[i]*s[k2]+s[k2]^2 f[k1][j-1]-2*s[i]*s[k1]+s[k1]^2 >= f[k2][j-1]-2*s[i]*s[k2]+s[k2]^2 ( f[k1][j-1]+s[k1]^2 ) - ( f[k2][j-1]+s[k2]^2 ) >= 2*s[i]*s[k1]-2*s[i]*s[k2] ( f[k1][j-1]+s[k1]^2 ) - ( f[k2][j-1]+s[k2]^2 ) / (s[k1]-s[k2]) <= 2*s[i] */ #include<cstdio> #include<iostream> #include<cstring> using namespace std; typedef long long LL; int a[3100],s[31000],list[3100]; LL f[3100][3100]; LL X(int k,int j) { return f[k][j-1]+s[k]*s[k]; } int Y(int k) { return s[k]; } double slope(int k1,int k2,int j) { return double(X(k1,j)-X(k2,j)) / double(Y(k1)-Y(k2)); } int main() { freopen("journey.in","r",stdin); freopen("journey.out","w",stdout); int n,m,sum=0; scanf("%d%d",&n,&m); s[0]=0;for(int i=1;i<=n;i++) { scanf("%d",&a[i]); s[i]=s[i-1]+a[i]; sum+=a[i]; f[i][1]=s[i]*s[i]; } for(int j=2;j<=m;j++) { int head=1,tail=1; list[1]=j-1; for(int i=j;i<=n;i++) { while(head<tail&&slope(list[head],list[head+1],j)<=2*s[i])head++; int x=list[head]; f[i][j]=f[x][j-1]+(s[i]-s[x])*(s[i]-s[x]); while(head<tail&&slope(list[tail-1],list[tail],j)>slope(list[tail],i,j))tail--; list[++tail]=i; } } printf("%lld\n",f[n][m]*m-sum*sum); return 0; }
pain and happy in the cruel world.