HDU 3480 (斜率优化)

来源:互联网 发布:淘宝定制的可强行退吗 编辑:程序博客网 时间:2024/06/05 04:29

题目链接:点击这里

题意: 给出一个数字集合S, 要求m个子集, 使得子集并等于S, 并且每一个子集的花费和最小. 一个集合的花费等于最大元素减去最小元素的平方.

显然贪心的想一下是最后肯定是数列排完序之后划分一下. 然后costi,j=(ajai)2, 转移方程就是fi=min{fj+(aiaj+1)2j<i}, 于是对于每一个下标, 直接枚举前面要n的复杂度, 可以确定j比k优的条件是
fj+(aiaj+1)2fk+(aiak+1)2

整理下就是
fj+a2j+1fka2k+12aj+12ak+1ai

然后用上斜率优化优化掉一个n就好了, 复杂度O(n*m).

#include <bits/stdc++.h>using namespace std;#define maxn 10005int dp[maxn][5005];int n, m, que[maxn];int a[maxn];int up (int i, int j, int k) {    return dp[i][k]+a[i+1]*a[i+1] - (dp[j][k]+a[j+1]*a[j+1]);}int down (int i, int j, int k) {    return 2*(a[i+1]-a[j+1]);}int main () {    int kase = 0, t;    scanf ("%d", &t);    while (t--) {        printf ("Case %d: ", ++kase);        scanf ("%d%d", &n, &m);        for (int i = 1; i <= n; i++) scanf ("%d", &a[i]);        if (m >= n) {            printf ("0\n");            continue;        }        m--;        sort (a+1, a+1+n);        for (int i = 1; i <= n; i++) dp[i][0] = (a[i]-a[1])*(a[i]-a[1]);        for (int k = 1; k <= m; k++) {            int L = 0, R = 0;            que[R++] = 0;            for (int i = 1; i <= n; i++) {                while (L+1 < R && up (que[L+1], que[L], k-1) <= a[i]*down (que[L+1], que[L], k-1))                    L++;                int j = que[L];                dp[i][k] = dp[j][k-1] + (a[i]-a[j+1])*(a[i]-a[j+1]);                while (L+1 < R && up (i, que[R-1], k-1)*down (que[R-1], que[R-2], k-1) <=                       up (que[R-1], que[R-2], k-1)*down (i, que[R-1], k-1))                    R--;                que[R++] = i;            }        }        printf ("%d\n", dp[n][m]);    }    return 0;}
0 0
原创粉丝点击