小Q同学为了准备今年的ICPC Regional,计划在天之内刷掉道题,每道题有一个难度值,其中第道题的难度值为。
然而处于半颓废状态中的小Q同学不希望在同一天中做难度差距悬殊的题目,定义第天中刷的题的难度的最大值减最小值为(如果第天没有刷题,则),那么整个计划的难度为。
小Q同学可以按照任意的顺序刷题,并且一天中可以刷任意多道题,但是每道题只需要做一次,现在小Q同学想知道完成这个计划的总难度的最小值是多少。
Input
第一行是一个正整数,表示测试数据的组数,
对于每组测试数据,
第一行是两个整数和,表示题数和天数,
第二行是个整数,表示每道题的难度值。
Output
对于每组测试数据,输出一个整数,表示整个计划的最小难度。
Sample Input
2 3 3 1 2 3 3 2 1 2 3
Sample Output
0 1
Hint
对于第一组样例,最优方案是一天刷一题。
对于第二组样例,一个最优方案是第一天刷难度值为1和2的题,第二天刷难度值为3的题。
n天刷m道题,m道题可以随意分配,每天的难度值是当天题目的最大最小难度之差的平方,求所有天加一起的难度最小值
解题思路:
将这些题的难度从小到大排好序(从大到小也可以),可以断定每天做的题一定是这里连续的区间,因为假设跳了n个,那么交换这个和当前区间的难度最大的那几个题,和下一天交换,答案一定更小。
之后用dp[i][j]表示第i天刷到第j题的最小值,那么dp[i][j]=min(dp[i-1][k]+(a[j]-a[k])^2)(k=1...j-1),dp[n][m]即为所求。
注意:INF要开的足够大,否则会wa
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<map>
#include<string.h>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#define C(a) memset(a,0,sizeof a)
#define C_1(a) memset(a,-1,sizeof a)
#define C_I(a) memset(a,0x3f,sizeof a)
using namespace std;
typedef long long ll;
const ll INF = 1000000000000000000ll;
const int maxn = 1e6 + 20;
int t[maxn];
ll a[maxn];
int ca;
ll dp[520][520];
int n, m;
int main()
{
int T; cin >> T;
while (T--)
{
C(t);
C(dp);
C(a);
ca = 0;
scanf("%d%d", &n, &m);
int x;
for (int i = 0; i<n; i++)
{
scanf("%d", &x);
if (t[x] == 0)a[ca++] = x;
t[x]++;
}
sort(a, a + ca);
if (ca <= m) { printf("0\n"); continue; }
for (int j = 0; j<ca; j++)dp[1][j] = (a[j] - a[0])*(a[j] - a[0]);
for (int i = 2; i <= m; i++)
{
dp[i][0] = 0;
for (int j = 1; j<ca; j++)
{
dp[i][j] = INF;
for (int k = 0; k<j; k++)
dp[i][j] = min(dp[i][j], dp[i - 1][k] + (a[j] - a[k + 1])*(a[j] - a[k + 1]));
}
}
cout << dp[m][ca - 1] << endl;
}
return 0;
}