zoukankan      html  css  js  c++  java
  • HDU 3480

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3480

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

    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.

    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

    题意:

    给出含有N元素的集合S,选取M个S的子集,要求满足SU S2 U … U SM = S;

    定义一个集合的最大元素为MAX,最小元素为MIN,它的花费为(MAX - MIN)2,现要求所有子集的总花费最少为多少。

    题解:

    先将S内元素从小到大排列,然后将这N个元素的序列分成M组(因为若有重叠元素,必然会使得花费增加);

    那么假设dp[i][j]为前i个数分成j组的最小花费,那么求出dp[N][M]即可回答问题;

    状态转移方程为dp[i][j] = min{ dp[k][j-1] + (S[i] - S[k+1])2 },j-1≤k<i;

    那么当j固定时,计算dp[i][j]时需要枚举k,若k可能取值到a,b两点,且j-1≤a<b<i,

    若有 dp[b][j-1] + (S[i] - S[b+1])2 ≤ dp[a][j-1] + (S[i] - S[a+1])2,则b点优于a点;

    将上式变形,得到:

    b点优于a点 <=> 

    再然后就是斜率优化的老套路了(斜率优化的详情查看斜率DP分类里之前的文章),就不再赘述。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=10000+5;
    
    int n,m,S[maxn];
    int dp[maxn][maxn];
    int q[maxn],head,tail;
    
    int up(int a,int b,int j) //g(a,b)的分子部分
    {
        return (dp[b][j-1]+S[b+1]*S[b+1])-(dp[a][j-1]+S[a+1]*S[a+1]);
    }
    int down(int a,int b) //g(a,b)的分母部分
    {
        return 2*S[b+1]-2*S[a+1];
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        for(int kase=1;kase<=t;kase++)
        {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++) scanf("%d",&S[i]);
            sort(S+1,S+n+1);
    
            for(int i=1;i<=n;i++) dp[i][1]=(S[i]-S[1])*(S[i]-S[1]);
            for(int j=2;j<=m;j++)
            {
                head=tail=0;
                q[tail++]=j-1;
                for(int i=j;i<=n;i++)
                {
                    while(head+1<tail)
                    {
                        int a=q[head], b=q[head+1];
                        if(up(a,b,j)<=S[i]*down(a,b)) head++; //g(a,b)<=S[i]
                        else break;
                    }
                    int k=q[head];
                    dp[i][j]=dp[k][j-1]+(S[i]-S[k+1])*(S[i]-S[k+1]);
    
                    while(head+1<tail)
                    {
                        int a=q[tail-2], b=q[tail-1];
                        if(up(a,b,j)*down(b,i)>=up(b,i,j)*down(a,b)) tail--; //g(a,b)>=g(b,i)
                        else break;
                    }
                    q[tail++]=i;
                }
            }
    
            printf("Case %d: %d
    ",kase,dp[n][m]);
        }
    }

    注意DP边界的初始化。

  • 相关阅读:
    函数中的不定长参数研究 *and**
    copy()与直接=赋值的区别
    python的位运算符
    python的list相关知识
    hadoop报错:hdfs.DFSClient: Exception in createBlockOutputStream
    转载计算机的潜意识的文章:机器学习的入门级经典读物
    完全分布式hadoop2.5.0安装 VMware下虚拟机centos6.4安装1主两从hadoop
    PE结构总导航
    利用函数指针绕过断点
    为什么Fun函数能够执行
  • 原文地址:https://www.cnblogs.com/dilthey/p/8878094.html
Copyright © 2011-2022 走看看