题目描述
传送门
题目大意:将n个数划分到m个集合中,每个集合的代价是集合中最大元素与最小元素差的平方。求划分的最小代价。
题解
这个问题可以贪心的想,必然是权值接近的分成一个集合。
那么我们只要把权值排序,问题就又变成了划分问题。
f[j][i]=min{f[k][i−1]+(val[j]−val[k+1])∗(val[j]−val[k+1])}
然后一如既往的用四边形不等式优化。。。。
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define inf 1000000000
using namespace std;
int val[10003],dp[10003][5003],s[10003][5003];
int n,m,T;
int pow(int x)
{
return x*x;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&T);
for (int t=1;t<=T;t++) {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&val[i]);
sort(val+1,val+n+1);
//for (int i=1;i<=n;i++) cout<<val[i]<<" ";
//cout<<endl;
memset(dp,0,sizeof(dp));
for (int i=1;i<=n;i++)
dp[i][1]=pow(val[i]-val[1]),s[i][1]=0;
for (int i=2;i<=m;i++) {
s[n+1][i]=n;
for (int j=n;j>i;j--) {
dp[j][i]=inf;
for (int k=s[j][i-1];k<=s[j+1][i];k++) {
int tmp=dp[k][i-1]+pow(val[j]-val[k+1]);
if (tmp<dp[j][i])
dp[j][i]=tmp,s[j][i]=k;
}
}
}
printf("Case %d: %d\n",t,dp[n][m]);
}
}