题意:将n个数分成m段,每段的代价为最大值减最小值的平方,为代价最小是多少n<=10000 ,m<=5000
题解:先拍好序,从小到大,这样绝对是花费最小的,不过怎么样来做呢?一定很容易想到dp
分段dp十分好想吧,f[i][j]表示前i个数,分成j个数的最小值。
w[i][j]区间包含性十分好证明,
平行四边不等性,可以很好证明,
对吧,这样很好理解
所以得出f[i][j]满足------>s[i][j-1]<=s[i][j]<=s[i+1][j]
这个得出来就ok了,但是这道题有点奇葩,s[i][j-1]以前就求好了,但是s[i+1][j]呢?所以
需要倒着dp,先求s[i+1][j]在去搞s[i][j];
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #define inf 2000000009 8 using namespace std; 9 10 int cas,n,m,now=0; 11 int a[10007]; 12 int f[10007][5007],s[10007][5007]; 13 14 int main() 15 { 16 scanf("%d",&cas); 17 while(cas--) 18 { 19 scanf("%d%d",&n,&m); 20 for (int i=1;i<=n;i++) 21 scanf("%d",&a[i]); 22 sort(a+1,a+n+1); 23 for (int i=1;i<=n;i++) 24 f[i][1]=(a[i]-a[1])*(a[i]-a[1]),s[i][1]=1; 25 for (int k=2;k<=m;k++) 26 { 27 s[n+1][k]=n; 28 for (int i=n;i>=k;i--) 29 { 30 f[i][k]=inf; 31 for (int j=s[i][k-1];j<=s[i+1][k];j++) 32 { 33 int t=f[j-1][k-1]+(a[i]-a[j])*(a[i]-a[j]); 34 if (t<f[i][k]) f[i][k]=t,s[i][k]=j; 35 } 36 } 37 } 38 printf("Case %d: %d\n",++now,f[n][m]); 39 } 40 }