hdu 3480 斜率dp

传送门

题意:

给你一个有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_pair
const int maxn = 10001;
ll dp[maxn][maxn/2];


typedef pair <ll, ll> Line;
#define k first
#define b second
struct 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 b

ll 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]);
    }
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值