3480 P
Problem Destribe
Little D is really interested in the theorem of sets recently. There’s a problem that confused him a long time. Let T be a set of integers. Let the MIN be the minimum integer in T and MAX be the maximum, then the cost of set T if defined as (MAX – MIN)^2. Now given an integer set S, we want to find out M subsets S1, S2, …, SM of S, such that
Input
The input contains multiple test cases. In the first line of the input there’s an integer T which is the number of test cases. Then the description of T test cases will be given. For any test case, the first line contains two integers N (≤ 10,000) and M (≤ 5,000). N is the number of elements in S (may be duplicated). M is the number of subsets that we want to get. In the next line, there will be N integers giving set S.
Output
For each test case, output one line containing exactly one integer, the minimal total cost. Take a look at the sample output for format.
Sample Input
2 3 2 1 2 4 4 2 4 7 10 1
Sample Output
Case 1: 1 Case 2: 18
Hint
The answer will fit into a 32-bit signed integer.
題意 : 把n個數字 分成m個集合。 每個集合的價值是 這個集合中 (max-min)^2。 輸出最
少的價值
思路 : 我們可以使用 dp[i][j] 代表 以 j 結尾 第 j 個集合的最小值
那麼可以容易的推出來 dp[i][j] = min { dp[k][j-1] + ( v[j] - v[k] ) * ( v[j] - v[k] ) } ;
但是這個演算法的時間複雜度是 O( n^3 ) 很容易 TLE ,因此我們需要用到斜率進行優化 ,
其實這個題幾乎是斜率優化的裸題了,沒學過的可以學習一下
AC code :
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e4+50;
const int maxm = 5e3+50;
ll dp[maxn][maxm] ,v[maxn] ;
int n ,m ;
int que[maxn] ,head ,tail ;
ll getdp(int i,int j,int k) {
return dp[k][j-1] + (v[i] - v[k + 1]) * (v[i] - v[k + 1]);
}
ll y(int j,int k,int q) {
return dp[k][j-1] + v[k + 1] * v[k + 1] - (dp[q][j-1] + v[q + 1] * v[q + 1]);
}
ll x(int k,int q) {
return 2 * ( v[k + 1] - v[q + 1] );
}
int main() {
int t ,ncase = 1 ; cin>>t;
while(t--) {
scanf("%d %d",&n ,&m );
for (int i = 1;i<=n;i++) scanf("%lld",&v[i] );
sort(v + 1 ,v + n + 1 );
for (int i = 1;i<=n;i++) dp[i][1] = (v[i] - v[1]) * (v[i] - v[1]);
for (int i = 2;i<=m;i++) {
head = tail = 0; que[tail ++] = i - 1;
for (int j = i;j<=n;j++) {
while(head + 1 < tail && y(i ,que[head+1] ,que[head]) < x(que[head+1] ,que[head]) * v[j] ) head ++;
dp[j][i] = getdp(j ,i ,que[head] );
while(head + 1 < tail && y(i ,que[tail-1] ,que[tail-2]) * x(j ,que[tail-1]) >= y(i ,j ,que[tail-1]) * x(que[tail-1] ,que[tail-2]) ) tail --;
que[tail ++] = j;
}
}
printf("Case %d: ",ncase++);
printf("%lld\n",dp[n][m]);
}
return 0;
}