zoukankan      html  css  js  c++  java
  • HDU-3045 Picnic Cows 【DP+斜率优化】

    题目链接

    题意

    有N只奶牛,每只奶牛有一个满意度,如果把一些奶牛分到一个组内,那么这些奶牛的满意度都会下降到组中满意度的最小值。现在规定每个组至少T只奶牛,求总的满意度变化的最小值

    分析

    从这个题中我学到了斜率DP中规定了转移距离的最小值时的处理方法(也就是i必须从小于等于i-T的状态转移而来)
    状态不难想出,先对奶牛的满意度排个序,设dp[i]为前i只奶牛分好组后的满意度下降最小值,显然有:

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

    其中j<=i-T
    考虑到对当前状态i,i-T+1~i-1都不能作为状态转移的来源,他们此时也都不应该出现在单调队列中。于是与往常每算完一个状态的值就将其放入队列中不同,我们控制入队的时间,也即若当前为i,才令状态i-T+1入队(注意要+1,因为下一个位置是i+1)。当然同时也要判断i-T+1本身要大于T才能入队。
    对应的处理也就是下面三行代码:

    pre=i-T+1;
    if(pre>=T) insert(pre);

    AC代码

    //HDU-3045 Picnic Cows
    //AC 2017-3-11 16:20:17
    //DP, slope trick
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=4e5+100;
    
    int N,T;
    long long dp[maxn],a[maxn];
    long long sum[maxn];
    int que[maxn],head,tail;
    
    long long getx(int j)
    {
        return a[j+1];
    }
    
    long long gety(int j)
    {
        return dp[j]-sum[j]+j*a[j+1];
    }
    
    void insert(int j)
    {
        while(tail>head+1&&
              (gety(j)-gety(que[tail-1]))*(getx(que[tail-1])-getx(que[tail-2]))<=
              (gety(que[tail-1])-gety(que[tail-2]))*(getx(j)-getx(que[tail-1])))
                --tail;
        que[tail++]=j;
        return;
    }
    
    int get_front(int i)
    {
        while(tail>head+1&&
              (gety(que[head+1])-gety(que[head]))<=i*(getx(que[head+1])-getx(que[head])))
                ++head;
        return que[head];
    }
    
    int main()
    {
        while(scanf("%d %d",&N,&T)!=EOF)
        {
            a[0]=dp[0]=sum[0]=0;
            for(int i=1;i<=N;++i)
                scanf("%lld",a+i);
            sort(a+1,a+1+N);
            for(int i=1;i<=N;++i)
                sum[i]=a[i]+sum[i-1];
            head=tail=0;
            insert(0);
            for(int i=1;i<=N;++i)
            {
                int pre=get_front(i);
                dp[i]=dp[pre]+sum[i]-sum[pre]+(pre-i)*a[pre+1];
                pre=i-T+1;
                if(pre>=T)
                    insert(pre);
            }
            printf("%lld
    ",dp[N]);
        }
        return 0;
    }
  • 相关阅读:
    NEO从入门到开窗(4)
    NEO从入门到开窗(3)
    NEO从入门到开窗(2)
    NEO从入门到开窗(1)
    重读大型网站技术架构
    c#并行编程
    关于使用CPU缓存的一个小栗子
    Visual Studio中从应用程序中调试SQL脚本
    JavaScript启示录
    LabVIEW工控二进制数据存储
  • 原文地址:https://www.cnblogs.com/DrCarlluo/p/6580568.html
Copyright © 2011-2022 走看看