hdu 3480 斜率dp

来源:互联网 发布:淘宝如何买到正品 编辑:程序博客网 时间:2024/06/05 14:38

传送门

题意:

给你一个有n个数的集合S,现在让你选出m个子集合,使这m个子集合并起来为S,并且每个集合的(max-min)之和要最小。

题解:

运用贪心的思想,肯定首先将全部的数排好序,然后设dp[i][j]表示前j个数分为i个集合的最优解。

则有dp[i][j]=min{dp[i-1][k]+(a[j]-a[k+1])2}(0<k<j)。

#include<bits/stdc++.h>using namespace std;#define ll long long#define mp make_pairconst int maxn = 10001;ll dp[maxn][maxn/2];typedef pair <ll, ll> Line;#define k first#define b secondstruct ConvexHull{    Line stk[maxn];    int l, r;    void init(){ l = r = 0; }    //sz r - l  [l,r)    bool cover(Line &a, Line &b, Line &c)    {        // line a and b cover line c        return (a.k - b.k) * (b.b - c.b) >= (b.b - a.b) * (c.k - b.k);        //  >= 下凸包 求最小值        //  <= 上凸包 求最大值    }    void add(Line p)    {        while(r - l > 1 && cover(p,stk[r-2],stk[r-1]))r--;        stk[r++] = p;    }    ll calc(ll x, Line l){ return l.k * x + l.b; }    ll ask(ll x)    {        while(r - l > 1 && calc(x,stk[l+1]) <= calc(x,stk[l]))l++;        return calc(x,stk[l]);    }}hull;#undef k#undef bll sq(ll x){ return x*x; }ll v[maxn];int n,m;int T;int main(){    scanf("%d",&T);    for(int cas=1;cas<=T;cas++)    {        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)        {            scanf("%lld",&v[i]);        }        sort(v+1,v+n+1);        dp[0][0]=0;        for(int i=1;i<=n;i++)            dp[i][1]=sq(v[i]-v[1]);        for(int _=2;_<=m;_++)        {            hull.init();            hull.add(mp(-2*v[1],sq(v[1])));            for(int i=1;i<=n;i++)            {                dp[i][_] = hull.ask(v[i]) + sq(v[i]);                hull.add( mp( -2*v[i+1],sq(v[i+1]) + dp[i][_-1] ) );            }        }        printf("Case %d: %lld\n",cas,dp[n][m]);    }}