zoukankan      html  css  js  c++  java
  • 【动态规划】2021年动态规划问题集

    商场有n个物品,每个物品有一个价格a[i],每个物品至多购买1次。商场有m个折扣活动,用(x[i],y[i])表示一次购买x[i]个物品可以免去最便宜的y[i]个物品的价格。问购买恰好k个物品的最小总价格。
    https://codeforces.com/contest/1154/problem/F

    前面的贪心很显然,排序贪心选最小的k个物品,每个x相同的折扣贪心选y最小的。后面的贪心并没想到,每次选择购买的物品都是连续的一段。最后设dp[i]表示购买了i个物品的最小值,然后枚举一次购买j个物品,用一个前缀和加速更新即可。

    msv(dp, LINF);
    cmin(dp[0], 0LL);
    for(int i = 1; i <= k; ++i) {
        for(int j = 1; j <= i; ++j)
            cmin(dp[i], dp[i - j] + sum(i - y[j] + 1, i));
    }
    printf("%lld
    ", dp[k]);
    

    https://codeforces.com/contest/883/problem/I
    将n个物品分为若干组,每组的大小至少为k,求每组的极差的最大值的最小值。

    求最大值的最小值,容易想到二分极差D,但可惜check不能贪心为“刚刚超过D的时候多分一组”,因为这样可能会导致最后一组不足k个。这里要换一种思路,设状态为dp[i]表示是否存在一种方法,把[1,i]的物品完整分为若干组,且满足每组极差不超过D,且每组的数量至少为k。那么转移为dp[i]|=dp[j],枚举j从0到i-k+1,且极差不超过D,这个是一个双指针确定的或和。

    bool check(int D) {
        dp[0] = 1;
        int L = 0, R = 0, cnt = 1;
        for(int i = 1; i <= n; ++i) {
            while((i - (R + 1 + 1) + 1) >= k) {
                ++R;
                cnt += dp[R];
            }
            while(a[i] - a[L + 1] > D) {
                cnt -= dp[L];
                ++L;
            }
            dp[i] = (L <= R) && (i - (R + 1) + 1 >= k) && (cnt > 0);
        }
        return dp[n];
    }
    
  • 相关阅读:
    HDU_1711 Number Sequence(KMP)
    快速排序+归并排序
    贪心算法
    HDU_1496 Equations && POJ_1840 Eqs(Hash)
    POJ_1328 Radar Installation(贪心)
    HDU_1055 && POJ_2054 Color a Tree(贪心)
    HDU_1754 I Hate It (线段树)
    哈希(Hash)表学习笔记
    jQuery插件datepicker的使用详解
    json总结
  • 原文地址:https://www.cnblogs.com/purinliang/p/14231545.html
Copyright © 2011-2022 走看看