HDU 3045 Picnic Cows 斜率优化DP

来源:互联网 发布:淘宝上面最便宜的卫衣 编辑:程序博客网 时间:2024/06/05 03:43

题意:John要组织N头牛去春游。每头牛有自己的高兴值。John需要把这些牛分成若干组,每组内至少有T头牛。每个牛的高兴值,都会降低为组内高兴值最小的牛的高兴值。John想最小化减少的值。
思路:首先考虑到,对于每一组,我们要知道组内最小值、组内所有牛的高兴值、组内牛的数量,就能求出该组降低的高兴值。
同时,因为牛的分配有无序性,我们可以先排序,这样最小值就可以非常容易的知道了。
定义sum[i]为前i头牛的高兴值的和。
定义dp[i]为,对前i头牛分组得到的最小值,可以得到状态转移方程:

dp[i]=min(dp[j]+sum i sum j (ij)a j+1 ) 

但是这样的复杂度是Θ(n 2 ) ,会超时。
上面的状态转移方程同样可以用单调队列优化,具体证明过程就不写了。
代码如下:

#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int MAX = 400100;typedef __int64 LL;LL a[MAX],sum[MAX];LL q[MAX],head,tail;LL dp[MAX];int main(void){    //freopen("input.txt","r",stdin);    LL N,T;    while(scanf("%I64d %I64d", &N,&T) != EOF){        sum[0] = 0;        memset(dp,0,sizeof(dp));        for(LL i = 1; i<= N; ++i)            scanf("%I64d", &a[i]);        sort(a + 1,a + N + 1);        for(LL i = 1; i <= N; ++i)            sum[i] = sum[i-1] + a[i];        head = tail = 0;        q[tail++] = 0;        dp[0] = 0;        for(LL i = T; i <= N; ++i){            while(head + 1 < tail){                LL p1= q[head],p2= q[head+1];                LL x1 = a[p1+1],x2 =a[p2+1];                LL y1 = dp[p1] - sum[p1] + p1 * x1;                LL y2 = dp[p2] - sum[p2] + p2 * x2;                if((y2 - y1) <= i * (x2 - x1) ) head++;                else break;            }            int k = q[head];            dp[i] = dp[k] + sum[i] - sum[k] - a[k+1] * (i - k);           // printf("%I64d %d\n",dp[i],k);            if(i >= 2 * T -1){                LL p3 = i - T + 1;                LL x3 = a[p3+1];                LL y3 = dp[p3] - sum[p3] + p3 * x3;                while(head+1 < tail){                    LL p1= q[tail-2],p2= q[tail-1];                    LL x1 = a[p1+1],x2 =a[p2+1];                    LL y1 = dp[p1] - sum[p1] + p1 * x1;                    LL y2 = dp[p2] - sum[p2] + p2 * x2;                    if((y2 - y1) * (x3 - x2) >= (y3 - y2) * (x2 - x1)) tail--;                    else break;                }                q[tail++] = p3;            }        }        printf("%I64d\n",dp[N]);    }    return 0;}
0 0
原创粉丝点击