Division
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 999999/400000 K (Java/Others)Total Submission(s): 5327 Accepted Submission(s): 2103
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
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
![](https://i-blog.csdnimg.cn/blog_migrate/3dd1058b5d51c7f6e78982cdf3fbbd51.jpeg)
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.
Sample Input
23 21 2 44 24 7 10 1
Sample Output
Case 1: 1Case 2: 18
题意:
给你n个点,要你分成m个集合,使得分成的这些集合的总价值最小,value+=(子集合里面的最大值-子集合里面的最小值)^2
解析:
其实就是两个状态的DP,第一个状态是集合元素,第二个状态是当前集合数
DP[i][j]为前i个元素分成j组的最小值
状态转移方程是dp[i][k]=min{dp[j][k-1]+(a[i]-a[j+1])^2} k<m,j<i
DP两个状态->二维数组
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long int lli;
const int MAXM = 5e3 +10;
const int MAXN = 1e4 +10;
#define INF 0x3f3f3f3f
//lli sum[MAXN];
lli xb[MAXN];
lli dp[MAXN][MAXM];
lli q[MAXN],head,tail;
lli n,m;
lli DP(int i,int j,int c)
{
return dp[j][c-1]+(xb[i]-xb[j+1])*(xb[i]-xb[j+1]);
}
lli UP(int i,int j,int c)
{
return dp[i][c-1]+xb[i+1]*xb[i+1]-dp[j][c-1]-xb[j+1]*xb[j+1];
}
lli DOWN(int i,int j)
{
return xb[i+1]-xb[j+1];
}
int main()
{
int t;
scanf("%d",&t);
int ncount=0;
while(t--)
{
scanf("%lld%lld",&n,&m);
ncount++;
for(int i=1;i<=n;i++)
{
scanf("%lld",&xb[i]);
}
sort(xb+1,xb+1+n);
dp[0][0]=0;
for(int i=1;i<=n;i++)
dp[i][1]=DP(i,0,0);
for(int j=2;j<=m;j++)
{
tail=head=0;
q[tail++]=0;
for(int i=1;i<=n;i++)
{
while(head+1<tail&&UP(q[head+1],q[head],j)<=2*xb[i]*DOWN(q[head+1],q[head]))
head++;
dp[i][j]=DP(i,q[head],j);
int p=i;
while(head+1<tail&&UP(p,q[tail-1],j)*DOWN(q[tail-1],q[tail-2])<=UP(q[tail-1],q[tail-2],j)*DOWN(p,q[tail-1]))
tail--;
q[tail++]=p;
}
}
printf("Case %d: %lld\n",ncount,dp[n][m]);
}
return 0;
}