zoukankan      html  css  js  c++  java
  • hdu 3045 Picnic Cows(斜率优化DP)

    题目链接:hdu 3045 Picnic Cows

    题意:

    1. 有n个奶牛分别有对应的兴趣值,现在对奶牛分组,每组成员不少于t,   
    2. 在每组中所有的成员兴趣值要减少到一致,问总共最少需要减少的兴趣值是多少。  

    题解:


    1. 分析:
      先对n个数进行排序,则可以分析出分组成员一定是连续的
      dp[i]表示前i个数得到的最少值
      则:从j~i作为一组
      dp[i]=dp[j-1]+sum[i]-sum[j-1]-(i-j+1)*s[j];//sum[i]表示前i个数的和
      =>dp[i]=dp[j-1]+sum[i]-sum[j-1]+(j-1)*s[j]-i*s[j];
      由于有i*s[j]这一项,所以无法直接在扫描数组的过程中用单调队列维护:
      dp[j-1]-sum[j-1]+(j-1)*s[j]-i*s[j]的最小值。
      考虑用斜率dp!
      假定k<j<=i-t以j~i作为一组比以k~i作为一组更优
      则:
      dp[j-1]+sum[i]-sum[j-1]-(i-j+1)*s[j] <= dp[k-1]+sum[i]-sum[k-1]-(i-k+1)*s[k]
      =>dp[j-1]+sum[i]-sum[j-1]+(j-1)*s[j]-i*s[j] <= dp[k-1]+sum[i]-sum[k-1]+(k-1)*s[k]-i*s[k]
      =>(dp[j-1]-sum[j-1]+(j-1)*s[j] - (dp[k-1]-sum[k-1]+(k-1)*s[k]))/(s[j]-s[k])<=i;//保证s[j]>=s[k]
      令:
      y1 = dp[j-1]-sum[j-1]+(j-1)*s[j]
      y2 = dp[k-1]-sum[k-1]+(k-1)*s[k]
      x1 = s[j]
      x2 = s[k]
      所以变成了:
      (y1 - y2)/(x1 - x2) <= i;
      斜率!
      只需要维护这个斜率即可

    以上转自stephen博客

     1 #include<bits/stdc++.h>
     2 #define F(i,a,b) for(int i=a;i<=b;++i)
     3 using namespace std;
     4 typedef long long ll;
     5 
     6 const int N=5e5+7;
     7 int n,t,Q[N];
     8 ll sum[N],s[N],dp[N];
     9 
    10 ll get_y(int j,int k)
    11 {
    12     return dp[j-1]-sum[j-1]+(j-1)*s[j]-(dp[k-1]-sum[k-1]+(k-1)*s[k]);
    13 }
    14 
    15 ll get_x(int j,int k){return s[j]-s[k];}
    16 
    17 int check(int i,int j,int k)//获取更优的点
    18 {
    19     return get_y(i,j)*get_x(j,k)<=get_y(j,k)*get_x(i,j);
    20 }
    21 
    22 int main()
    23 {
    24     while(~scanf("%d%d",&n,&t))
    25     {
    26         F(i,1,n)scanf("%lld",s+i);
    27         sort(s+1,s+1+n);
    28         F(i,1,n)sum[i]=sum[i-1]+s[i];
    29         int en=2*t-1;
    30         F(i,t,en)dp[i]=sum[i]-i*s[1];//从t到2*t-1都只能分到一组里
    31         int head=1,tail=0,st=2*t;
    32         F(i,st,n)
    33         {
    34             while(head<tail&&check(i-t+1,Q[tail],Q[tail-1]))tail--;
    35             Q[++tail]=i-t+1;
    36             while(head<tail&&get_y(Q[head+1],Q[head])<=get_x(Q[head+1],Q[head])*i)head++;
    37             dp[i]=dp[Q[head]-1]+sum[i]-sum[Q[head]-1]-(i-Q[head]+1)*s[Q[head]];
    38         }
    39         printf("%lld
    ",dp[n]);
    40     }
    41     return 0;
    42 }
    View Code
  • 相关阅读:
    工厂增强
    面试题
    SpringBean生命周期及作用域
    字符串
    带参数方法实例
    带参数方法
    人机猜拳
    类的无参方法
    类和对象实例2
    类和对象实例1
  • 原文地址:https://www.cnblogs.com/bin-gege/p/6135705.html
Copyright © 2011-2022 走看看