Division
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 999999/400000 K (Java/Others)
Total Submission(s): 5883 Accepted Submission(s): 2337
Problem Description
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
![](http://acm.hdu.edu.cn/data/images/C295-1003-1.jpg)
and the total cost of each subset is minimal.
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
![](http://acm.hdu.edu.cn/data/images/C295-1003-1.jpg)
and the total cost of each subset is minimal.
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.
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.
也是可以用斜率优化的一个dp
dp[i][j] 表示用j个数 划分 i个集合的最小花费
则 dp[i][j] = min{ dp[i-1][k] + (a[j]-a[k+1])^2 } (i-1<=k<j)
同理 假设 两个 j,k 使得 cost[j] <= cost[k] 得到一个斜率式子
然后用单调队列 优化一下 就可以了
#include <iostream> #include <cstdio> #include <string.h> #include <algorithm> using namespace std; const int N = 1e4+10; const int M = 5e3+10; #define rep(i,l,r) for(int i=l;i<=r;i++) int n,m; int a[N], dp[M][N], Q[N]; void init() { scanf("%d %d", &n, &m); rep(i,1,n) scanf("%d",&a[i]); sort(a+1,a+1+n); } /* 朴素 o(m*n*n) void solve() { memset(dp,0x3f,sizeof(dp)); dp[0][0]=0; rep(i,1,m) { rep(j,i,n) { rep(k,i-1,j-1) { dp[i][j] = min(dp[i][j], dp[i-1][k] + (a[j]-a[k+1])*(a[j]-a[k+1])); } } } printf("%d ", dp[m][n]); } */ void solve() { memset(dp,0x3f,sizeof(dp)); dp[0][0] = 0; rep(i,1,m) { int st=0,ed=0; Q[ed++] = i-1; rep(j,i,n) { while (st+1 < ed) { int k1 = Q[st]; int k2 = Q[st+1]; int x1 = a[k1+1]; int x2 = a[k2+1]; int y1 = dp[i-1][k1] + a[k1+1]*a[k1+1]; int y2 = dp[i-1][k2] + a[k2+1]*a[k2+1]; if(y2 - y1 <= 2 * a[j] * (x2 - x1)) st++; else break; } int k = Q[st]; dp[i][j] = dp[i-1][k] + (a[j] - a[k+1]) * (a[j] - a[k+1]); while (st+1 < ed) { int k1 = Q[ed-2], k2 = Q[ed-1], k3 = j; int x1 = a[k1+1], x2 = a[k2+1], x3 = a[j+1]; int y1 = dp[i-1][k1] + a[k1+1]*a[k1+1]; int y2 = dp[i-1][k2] + a[k2+1]*a[k2+1]; int y3 = dp[i-1][k3] + a[k3+1]*a[k3+1]; if((y3-y2)*(x2-x1) <=(y2-y1)*(x3-x2)) ed--; else break; } Q[ed++] = j; } } } int main () { int T; scanf("%d",&T); rep(cas,1,T) { init(); solve(); printf("Case %d: %d ",cas,dp[m][n]); } return 0; }