BNU 51640 Training Plan DP

Training Plan

小Q同学为了准备今年的ICPC Regional,计划在m天之内刷掉n道题,每道题有一个难度值,其中第i道题的难度值为a[i]

然而处于半颓废状态中的小Q同学不希望在同一天中做难度差距悬殊的题目,定义第i天中刷的题的难度的最大值减最小值为d[i](如果第i天没有刷题,则d[i]=0),那么整个计划的难度为\sum_{i=1}^{m}{d^2[i]}

小Q同学可以按照任意的顺序刷题,并且一天中可以刷任意多道题,但是每道题只需要做一次,现在小Q同学想知道完成这个计划的总难度的最小值是多少。

 

Input

第一行是一个正整数T(\leq 10),表示测试数据的组数,

对于每组测试数据,

第一行是两个整数n(1\leq n \leq 500)m(1\leq m \leq 500),表示题数和天数,

第二行是n个整数a[i](0\leq a[i]\leq 1000000),表示每道题的难度值。

 

Output

对于每组测试数据,输出一个整数,表示整个计划的最小难度。

 

Sample Input

2
3 3
1 2 3
3 2
1 2 3

Sample Output

0
1

Hint

对于第一组样例,最优方案是一天刷一题。

对于第二组样例,一个最优方案是第一天刷难度值为1和2的题,第二天刷难度值为3的题。

 

Source

题解:
  我们从小到大选择 就是将其分为m份
  设定dp[i][j] 为前i天刷了j题的最小答案
  转移为:
  dp[i][j] = min{dp[i-1][j](选择这天不刷题), dp[i-1][k] + (a[j]- [k+1]) 1<=k<=j }
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include<map>
#include<queue>
using namespace std;
const int N = 1e3+10, M = 30005, mod = 1e9 + 7, inf = 1e9+1000;
typedef long long ll;


ll dp[N][N];
int n,m,a[N];
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++) dp[0][i] = 1e18;
        dp[0][0] = 0;
        for(int i=1;i<=m;i++) {
            for(int j=1;j<=n;j++) {
                dp[i][j] = dp[i-1][j];
                for(int k=1;k<=j;k++) {
                    dp[i][j] = min(dp[i][j], dp[i-1][k-1] + abs(a[j]-a[k])*1ll*abs(a[j]-a[k]));
                }
            }
        }
        cout<<dp[m][n]<<endl;
    }
    return 0;
}

 

posted @ 2016-04-24 17:01  meekyan  阅读(235)  评论(0编辑  收藏  举报