首先从小到大排序。
然后设 dp[i][j]表示前j个数分成i组的最小花费。
则 dp[i][j]=min{dp[i-1][k]+(a[j]-a[k+1])^2} i-1<=k<j;
然后是斜率优化,自己整理一下就出来了。就不多说了。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 10111
unsigned int dp[MAX/2][MAX];
unsigned int s[MAX];
int q[MAX];
int N,M,head,tail;
int T,casei;
int getup(int i,int k2,int k1)
{
return dp[i-1][k1]+s[k1+1]*s[k1+1]-(dp[i-1][k2]+s[k2+1]*s[k2+1]);
}
int main()
{
int i,j;
scanf("%d",&T);
while(T--)
{
casei++;
scanf("%d%d",&N,&M);
for(i=1;i<=N;i++)
scanf("%d",&s[i]);
sort(s+1,s+N+1);
for(i=1;i<=N;i++)
dp[1][i]=(s[i]-s[1])*(s[i]-s[1]);
for(i=2;i<=M;i++)
{
head=tail=0;
q[tail++]=i-1; //注意这里,因为如果是i的话,就可能出现dp[i-1][i]的情况,所以要是i-1。
for(j=i;j<=N;j++)
{
while(head+1<tail&&getup(i,q[head],q[head+1])<=2*s[j]*(s[q[head+1]+1]-s[q[head]+1]))
head++;
dp[i][j]=dp[i-1][q[head]]+(s[j]-s[q[head]+1])*(s[j]-s[q[head]+1]);
while(head+1<tail&&getup(i,q[tail-1],j)*(s[q[tail-1]+1]-s[q[tail-2]+1])<=(s[j+1]-s[q[tail-1]+1])*getup(i,q[tail-2],q[tail-1]))
tail--;
q[tail++]=j;
}
}
printf("Case %d: %d\n",casei,dp[M][N]);
}
return 0;
}