1. 程式人生 > >bzoj 4518: [Sdoi2016]征途

bzoj 4518: [Sdoi2016]征途

題意:把n段路分成m天走,求每天走的路程的方差的最小值。輸出方差*m^2。
題解:斜率優化
我們先推一推公式。

v×m2=mi=1(xix¯)2m×m2=i=1m(x2i2xix¯+x¯2)×m=i=1m(mx2i2xis)+sum2然後直接搞就好了。
貌似可以劃得更簡= =不管了反正能過
f[i][j]表示前i段路分成j天最小的mi=1(mx2i2xis)
斜率:f[k][o]f[j][o]+msum[k]sum[k]msum[j]sum[j]+2sum[n]sum[k]2sum[n]sum[j]sum[k]sum[j]2msum[i]
滾也懶的滾了。。。
程式碼:
#include<cstdio>
#include<cstring> int n,m,a[3010],sum[3010],f[3010][3010],q[3010][3010],st[3010],ed[3010]; double slp(int k,int j,int o) { return double(f[k][o]-f[j][o]+m*sum[k]*sum[k]-m*sum[j]*sum[j]+2*sum[n]*sum[k]-2*sum[n]*sum[j])/(sum[k]-sum[j]); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf
("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } for(int j=0;j<m;j++) { for(int i=1;i<=n;i++) { while(st[j]<ed[j]&&slp(q[j][st[j]],q[j][st[j]+1],j)<2*m*sum[i]) st[j]++; int hh=q[j][st[j]],x=sum[i]-sum[hh]; f[i][j+1
]=f[hh][j]+m*x*x-2*sum[n]*x; while(st[j+1]<ed[j+1]&&slp(q[j+1][ed[j+1]-1],q[j+1][ed[j+1]],j+1)>slp(q[j+1][ed[j+1]],i,j+1)) ed[j+1]--; q[j+1][++ed[j+1]]=i; } } printf("%d",f[n][m]+sum[n]*sum[n]); }