小Q同学为了准备今年的ICPC Regional,计划在天之内刷掉道题,每道题有一个难度值,其中第道题的难度值为。
然而处于半颓废状态中的小Q同学不希望在同一天中做难度差距悬殊的题目,定义第天中刷的题的难度的最大值减最小值为(如果第天没有刷题,则),那么整个计划的难度为。
小Q同学可以按照任意的顺序刷题,并且一天中可以刷任意多道题,但是每道题只需要做一次,现在小Q同学想知道完成这个计划的总难度的最小值是多少。
第一行是一个正整数,表示测试数据的组数,
对于每组测试数据,
第一行是两个整数和,表示题数和天数,
第二行是个整数,表示每道题的难度值。
对于每组测试数据,输出一个整数,表示整个计划的最小难度。
2 3 3 1 2 3 3 2 1 2 3
0 1
对于第一组样例,最优方案是一天刷一题。
对于第二组样例,一个最优方案是第一天刷难度值为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; }