hdu3045 Picnic Cows 斜率优化dp

来源:互联网 发布:vip视频解析端口原理 编辑:程序博客网 时间:2024/05/16 12:59

题目大意:
给出一个有N (1<=N<=400000)个正数的序列,要求把序列分成若干组(可以打乱顺序),每组的元素个数不能小于T (1 < T <= N)。每一组的代价是每个元素与最小元素的差之和,总代价是每个组的代价之和,求总代价的最小值。

承接上一篇再刷一道题,唯一不同就是有一个区间限定。
不过多阐述了,直接贴代码。要看斜率优化分析,请转至
斜率优化

/*首先 sort 从小到大排序。然后 dp[i] 前 i 个数分隔得到的最小值。则  dp[i]= min{dp[j]+(sum[i]-sum[j])-a[j+1](i-j)}    k<=j<i-t+1.之后就是斜率优化了。*/#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>#define LL long longusing namespace std;const int MAXN = 400010;int que[MAXN];LL sum[MAXN], a[MAXN], dp[MAXN];LL getDP(int i, int j){    return dp[j] + (sum[i] - sum[j]) - a[j + 1] * (i - j);}LL getUP(int j, int k){    return dp[j] - sum[j] + j * a[j + 1] - dp[k] + sum[k] - k * a[k + 1];}LL getDOWN(int j, int k){    return a[j + 1] - a[k + 1];}/*定义状态dp[i]表示排序后前i个数分组后的最小代价。dp[i] = dp[j] + (sum[i] –sum[j]) –a[j+1] * (i-j)dp[i] = dp[k] + (sum[i] –sum[k]) –a[k+1] * (i-k)斜率优化维护一个凸包,使队首的第一个线段的斜率最优需要 dp[j] + (sum[i] –sum[j]) – a[j+1] * (i-j) > dp[k] + (sum[i] –sum[k]) - a[k+1] * (i-k)所以 dp[j] + sum[i] –sum[j] –a[j+1] * i + a[j+1] * j > dp[k] + sum[i] - sum[k] - a[k+1] * i + a[k+1] * k)所以 dp[j] –sum[j] –a[j+1] * i + a[j+1] * j > dp[k] - sum[k] - a[k+1] * i + a[k+1] * k)所以 dp[j] - dp[k] - sum[j] + sum[k] + a[j+1] * j - a[k+1] * k > i * (a[j+1] - a[k+1])     UP > i * DOWN*/int main(){    int n, t;    int head, tail;    while(scanf("%d%d", &n, &t) == 2){        dp[0] = sum[0] = a[0] = 0;        for(int i=1;i<=n;i++){            scanf("%I64d", &a[i]);        }        sort(a+1, a+n+1);        for(int i=1; i<=n; i++)            sum[i] = sum[i-1] + a[i];        head = tail = 0;        que[tail++] = 0;        for(int i=1; i<=n; i++){            while(head + 1 < tail             && getUP(que[head+1], que[head])                <= i * getDOWN(que[head+1], que[head])) head++;            dp[i] = getDP(i, que[head]);            int j = i - t + 1;//不能超过            if(j < t) continue;            while(head + 1 < tail             && getUP(j, que[tail-1]) * getDOWN(que[tail-1], que[tail-2])                <= getUP(que[tail-1], que[tail-2]) * getDOWN(j, que[tail-1])) tail--;               /*原型是                getUP(j, que[tail-1]) / getDOWN(j, que[tail-1])               <= getUP(que[tail-1], que[tail-2]) / getDOWN(que[tail-1], que[tail-2])               但是为了防止炸精度,用交叉相乘                */            que[tail++] = j;        }        printf("%I64d\n", dp[n]);    }    return 0;}
0 0
原创粉丝点击