[HDU3480]Division

Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 999999/400000 K (Java/Others)

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 T T be a set of integers. Let the M I N MIN MIN be the minimum integer in T T T and M A X MAX MAX be the maximum, then the cost of set T if defined as ( M A X – M I N ) 2 (MAX – MIN)^2 (MAXMIN)2. Now given an integer set S S S, we want to find out M M M subsets S 1 , S 2 , … , S M S_1, S_2, …, S_M S1,S2,,SM of S S S, such that
在这里插入图片描述
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 ) N (≤ 10,000) N(10,000) and M ( ≤ 5 , 000 ) M (≤ 5,000) M(5,000). N N N is the number of elements in S S S (may be duplicated). M M M is the number of subsets that we want to get. In the next line, there will be N N N integers giving set S S 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.

Source
2010 ACM-ICPC Multi-University Training Contest(5)——Host by BJTU

题意:
n n n个数字分成 m m m份每份的代价是 ( 最 大 数 − 最 小 数 ) 2 (最大数-最小数)^2 ()2,求最小代价

题解:
我们可以贪心的知道如果把排序之后连续的一段数字分成一份,那么将会是最优的。
那么之后我们就可以设 f [ i ] [ j ] f[i][j] f[i][j]是前 i i i个数字分成 j j j份之后最小代价是多少。
得出DP方程 f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ k ] [ j ] + ( a [ i ] − a [ k + 1 ] ) ∗ ( a [ i ] − a [ k + 1 ] ) ) f[i][j]=min(f[i][j],f[k][j]+(a[i]-a[k+1])*(a[i]-a[k+1])) f[i][j]=min(f[i][j],f[k][j]+(a[i]a[k+1])(a[i]a[k+1]))
然后用四边形不等式优化之后再滚动数组,就可以过了。

#include<bits/stdc++.h>
#define LiangJiaJun main
#define INF 19991227000LL
#define ll long long
using namespace std;
ll SQR(ll A){return A*A;}
ll f[10004][2];
int s[10004][5004];
int n,m;
int a[10004];

int w33ha(int CASE){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    memset(f,0,sizeof(f));
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=m+1;j++)
            s[i][j]=0;
    for(int i=1;i<=n;i++){
        f[i][1]=SQR(1LL*(a[i]-a[1]));
        s[i][1]=0;
        s[i][i]=i;
    }
    for(int j=2;j<=m;j++){
        s[n+1][j]=n;
        for(int i=n;i>=j;i--){
            f[i][j&1]=INF;
            for(int k=s[i][j-1];k<=s[i+1][j];k++){
                if(f[i][j&1]>f[k][(j-1)&1]+SQR(1LL*(a[i]-a[k+1]))){
                    f[i][j&1]=f[k][(j-1)&1]+SQR(1LL*(a[i]-a[k+1]));
                    s[i][j]=k;
                }
            }
        }
    }
    printf("Case %d: %lld\n",CASE,f[n][m&1]);
    return 0;
}
int LiangJiaJun(){
    int T;scanf("%d",&T);
    for(int i=1;i<=T;i++)w33ha(i);
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值