bzoj 4518: [Sdoi2016]征途
阿新 • • 發佈:2019-01-22
題意:把n段路分成m天走,求每天走的路程的方差的最小值。輸出方差*m^2。
題解:斜率優化
我們先推一推公式。
貌似可以劃得更簡= =
f[i][j]表示前i段路分成j天最小的
斜率:
滾也懶的滾了。。。
程式碼:
#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]);
}