设f[i][j]为前i个邮局放前j个村庄,第i个恰好放第j个的情况
那么f[i][j]=min(f[i-1][k]+cost(k+1,j-1));
而我们要确定中间那个到2边哪个更近的分界点有点困难,也就是处理出这个转移的cost有点困难
我们设x为第一个离j最近或者离jk一样近的村庄则a[j]-a[x]<a[x]-a[k]
即a[x]>(a[j]+a[k])/2 考虑到小数问题,用upper_bound就可以完美解决
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxl 310
#define inf 2000000001
using namespace std;
int n,m,ans;
int a[maxl],sum[maxl];
int f[32][maxl];
void prework()
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
}
void mainwork()
{
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
f[i][j]=inf;
for(int j=1;j<=n;j++)
f[1][j]=j*a[j]-sum[j];
int llen,rlen,x,cost;
for(int i=2;i<=m;i++)
for(int j=i;j<=n-(m-i);j++)
for(int k=i-1;k<j;k++)
{
x=upper_bound(a+k,a+j,(a[j]+a[k])/2)-a;
llen=x-k-1;rlen=j-x+1;
cost=f[i-1][k]+sum[x-1]-sum[k]-llen*a[k]+
rlen*a[j]-(sum[j]-sum[x-1]);
f[i][j]=min(f[i][j],cost);
}
ans=inf;
for(int j=m+1;j<=n;j++)
ans=min(ans,f[m][j]+sum[n]-sum[j]-(n-j)*a[j]);
}
void print()
{
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
prework();
mainwork();
print();
}
return 0;
}