zoukankan      html  css  js  c++  java
  • [USACO10NOV]购买饲料Buying Feed 单调队列优化DP

    题目描述

    约翰开车来到镇上,他要带 KKK 吨饲料回家。运送饲料是需要花钱的,如果他的车上有 XXX 吨饲料,每公里就要花费 X2X^2X2 元,开车D公里就需要 D×X2D imes X^2D×X2 元。约翰可以从 NNN 家商店购买饲料,所有商店都在一个坐标轴上,第 iii 家店的位置是 XiX_iXi ,饲料的售价为每吨 CiC_iCi 元,库存为 FiF_iFi

    约翰从坐标 X=0X=0X=0 开始沿坐标轴正方向前进,他家在坐标 X=EX=EX=E 上。为了带 KKK 吨饲料回家,约翰最少的花费是多少呢?假设所有商店的库存之和不会少于 KKK 。

    举个例子,假设有三家商店,情况如下所示:

    坐标X=1X=1X=1X=3X=3X=3X=4X=4X=4E=5E=5E=5
    库存 111 111 111
    售价 111 222 222

    如果 K=2K=2K=2 ,约翰的最优选择是在离家较近的两家商店购买饲料,则花在路上的钱是 1+4=51+4=51+4=5 ,花在商店的钱是 2+2=42+2=42+2=4 ,共需要 999 元。

    输入输出格式

    输入格式:

    111 行:三个整数 K,E,NK,E,NK,E,N 第 2..N+12..N+12..N+1 行:第 i+1i+1i+1 行的三个整数代表, Xi,Fi,CiX_i,F_i,C_iXi,Fi,Ci .

    输出格式:

    一个整数,代表最小花费

    输入输出样例

    输入样例#1: 
    2 5 3
    3 1 2
    4 1 2
    1 1 1
    输出样例#1: 
    9

    提交地址:Luogu4544

    我们发现, 最优的情况肯定是从家里往前走,走到要到达想要到的最远的商店, 往回走的时候再买东西;
    这就提示我们, 我们要先对坐标排序, 然后设dp[i][j],表示到了第i个商店, 在第i个商店之前买了j个东西的最小花费;
    dp[i][j]=min(dp[i-1][p]+dis[i]*j*j+w[i-1]*(j-p));
    什么意思呢?
    我们枚举一个p, 表示第i-1个商店时有p个货物,那么显然在i-1个商店买了(j-p)个货物,算上在第i-1个商店的花费,加上从i-1到i的路费,就是dp[i][j];
    复杂度nk^2, 妥妥的炸;
    考虑优化;
    发现转移式子里有min,自觉地想到了单调队列
    我们对式子进行一波变形。
    dp[i-1][p] - w[i-1]*p + dis[i]*j*j + w[i-1]*j;
    我们发现, 在i和j变化的时候,只有p是在变的,所以我们单调队列里放p;
    怎么处理呢?
    如果(j-q.front() > F[i-1])就pop掉队首, 因为我们要在i-1商店买的货物大于了第i-1个店的库存;
    如果o=q.back(), dp[i-1][o]-w[i-1]*o >= dp[i-1][j]-w[i-1]*j, 就pop掉队尾;显然;
    (写反了这个↑还能A, 数据太水了)
    要注意的是,要把自己的家也当成一个点,这样dp[n][k]才是最后的答案!
    然后注意开long long;
    Code:
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <queue>
     6 using namespace std;
     7 #define int long long
     8 
     9 inline int read()
    10 {
    11     int res=0;bool fl=0;char ch=getchar();
    12     while(!isdigit(ch)){if(ch=='-')fl=1;ch=getchar();
    13     }while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch-'0');ch=getchar();
    14     }return fl?-res:res;
    15 }
    16 
    17 int n, k, e;
    18 
    19 struct date
    20 {
    21     int pos;
    22     int F;
    23     int w;
    24     friend bool operator <(date a, date b)
    25     {
    26         return a.pos < b.pos;
    27     }
    28 }fam[1000010];
    29 
    30 int dp[510][10010];
    31 
    32 signed main()
    33 {
    34     k = read(), e = read(), n = read();
    35     
    36     for (register int i = 1 ; i <= n ; i ++)
    37     {
    38         fam[i].pos = read(), fam[i].F = read(), fam[i].w = read();
    39     }
    40     
    41     fam[++n] = (date){e, 0, 0};
    42     
    43     sort(fam + 1, fam + 1 + n);
    44     
    45     memset(dp, 0x3f, sizeof dp);
    46     
    47     dp[0][0] = 0;
    48     
    49     for (register int i = 1 ; i <= n ; i ++)
    50     {
    51         deque <int> q; 
    52         for (register int j = 0 ; j <= k ; j ++) 
    53         {            
    54             while (!q.empty() and j - q.front() > fam[i-1].F) q.pop_front(); //要买的大于上一个店的存储 
    55             if (dp[i-1][j] != 0x3f3f3f3f)
    56             {
    57                 while (!q.empty() and dp[i-1][q.back()] - fam[i-1].w * q.back() >= dp[i-1][j] - fam[i-1].w * j) q.pop_back();
    58                 q.push_back(j);
    59             }
    60             int o = q.front();
    61             if (!q.empty()) dp[i][j] = dp[i-1][o] - fam[i-1].w * o + (fam[i].pos - fam[i-1].pos) * j * j + fam[i-1].w * j;
    62         }
    63     }
    64     
    65     cout << dp[n][k] << endl;
    66     return 0;
    67     
    68 }
    
    
    
     
  • 相关阅读:
    memcached使用入门
    winform代码生成器(三)
    Spark + sbt + IDEA + HelloWorld + MacOS
    CentOS下Hive搭建
    36. 有效的数独
    HADOOP依赖
    判别数字图片能否「一笔完成」
    【网易微专业】图表绘制工具Matplotlib
    【18.065】Lecture2
    【18.065】Lecture1
  • 原文地址:https://www.cnblogs.com/BriMon/p/9129917.html
Copyright © 2011-2022 走看看