码迷,mamicode.com
首页 > 其他好文 > 详细

Division HDU - 3480 斜率dp

时间:2020-03-18 18:27:15      阅读:60      评论:0      收藏:0      [点我收藏+]

标签:space   子集   cin   最小   while   for   using   scan   printf   

//将含有N个元素的一个集合分成M个子集,使得每个子集的最大值与最小值平方差的和最小。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e4+50;
const int maxm = 5e3+50;
ll dp[maxn][maxm] ,v[maxn] ;
int n ,m ;
int q[maxn] ,r,l ;
ll getdp(int i,int j,int k) {
    return dp[k][j-1] + (v[i] - v[k + 1]) * (v[i] - v[k + 1]);
}
ll y(int j,int k,int q) {
    return dp[k][j-1] + v[k + 1] * v[k + 1] - (dp[q][j-1] + v[q + 1] * v[q + 1]);
}
ll x(int k,int q) {
    return 2 * ( v[k + 1] - v[q + 1] );
}
int main() {
    int t ,ncase = 1 ;
    cin>>t;
    while(t--) {
        scanf("%d %d",&n ,&m );
        for (int i = 1; i<=n; i++) 
            scanf("%lld",&v[i] );
        sort(v + 1 ,v + n + 1 );
        for (int i = 1; i<=n; i++) 
            dp[i][1] = (v[i] - v[1]) * (v[i] - v[1]);
        for (int i = 2; i<=m; i++) {
            l = r = 0;
            q[0] = i - 1;
            for (int j = i; j<=n; j++) {
                while(l  < r && y(i ,q[l+1] ,q[l]) < x(q[l+1] ,q[l]) * v[j] ) 
                    l ++;
                dp[j][i] = getdp(j ,i ,q[l] );
                while(l  < r && y(i ,q[r] ,q[r-1]) * x(j ,q[r]) >= y(i ,j ,q[r]) * x(q[r] ,q[r-1]) ) 
                    r --;
                q[++r] = j;
            }
        }
        printf("Case %d: ",ncase++);
        printf("%lld\n",dp[n][m]);
    }
    return 0;
}

Division HDU - 3480 斜率dp

标签:space   子集   cin   最小   while   for   using   scan   printf   

原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12519135.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!