题意:把n段路分成m天走,求每天走的路程的方差的最小值。输出方差*m^2。
题解:斜率优化
我们先推一推公式。
v×m2=∑mi=1(xi−x¯)2m×m2=∑i=1m(x2i−2xix¯+x¯2)×m=∑i=1m(mx2i−2xis)+sum2
然后直接搞就好了。
貌似可以划得更简= =
f[i][j]表示前i段路分成j天最小的 ∑mi=1(mx2i−2xis)
斜率:
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]≤2∗m∗sum[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]);
}