• 力扣天池赛-221021天池-04. 意外惊喜(分治优化dp)


    题目

    某电商平台举办了一个用户抽奖活动,奖池中共有若干个礼包,每个礼包中包含一些礼物。 present[i][j] 表示第 i 个礼包第 j 件礼(下标从 0 开始)物的价值。抽奖规则如下:

    • 每个礼包中的礼物摆放是有顺序的,你必须从第 0 件礼物开始打开;
    • 对于同一个礼包中的礼物,必须在打开该礼包的第 i 个礼物之后,才能打开第 i+1 个礼物;
    • 每个礼物包中的礼物价值 非严格递增

    参加活动的用户总共可以打开礼物 limit 次,请返回用户能够获得的 最大 礼物价值总和。

    提示:

    • 1 <= present.length <= 2000
    • 1 <= present[i].length <= 1000
    • 1 <= present[i][j] <= present[i][j+1] <= 10^5
    • 1 <= limit <= 1000

    思路来源

    灵茶山艾府(0x3f)的力扣讲解

    题解

    性质:最多只有一个礼包不全取

    反证法,考虑同时有两个礼包不全取,

    1 3 5 7 9

    2 4 6 8 8

    如一个礼包取了1、3、5,另一个礼包取了2、4、6,

    则可以用调整法,如用6和7、5和8比较,决定一个礼包可不可以局部调整

    由7不小于6,知7后面的数(这里为9)一定不小于6前面的数(这里为4),因为序列非严格递增

    但是,这个性质并不能实际用于局部调整,因为可能24688的和比13579的和大,

    所以,考虑枚举这个不全取的礼包,其他全取的礼包做01背包即可

    当答案枚举到i(0<=i

    1.考虑用倍增优化背包?(预处理以i为起点,长度为1、2、4…的背包的答案)

    不太行,实际两个背包合并的复杂度是O(1000*1000)的,不如背包内放一个物品的复杂度O(1000)

    2.考虑用背包撤销?(把物品放进去,撤销的时候做一遍逆操作)

    不太行,max信息无法撤销,sum这种各个贡献独立的才可撤销

    3.考虑用分治优化背包,设当前区间[l,r],

    先用tmp数组把当前dp暂存下来,把[mid+1,r]的01背包算进去后,再递归进[l,mid]

    用tmp数组将dp恢复,把[l,mid]的01背包算进去后,再递归进[mid+1,r]

    在进入一个区间之前,这个区间的补集已经在之前的递归中算过了,

    在递归每一层的区间时,算区间的另一半背包的答案,

    当l=r的时候,即枚举当前背包是那个不全取的背包,更新答案

    代码

    1. class Solution {
    2. public:
    3. int ans,up,a[2005],sz[2005],dp[1005];
    4. void dfs(vectorint>>& p,int l,int r){
    5. if(l==r){
    6. ans=max(ans,dp[up]);
    7. int cur=0;
    8. for(int i=1;i<=min(up,sz[l]);++i){
    9. cur+=p[l][i-1];
    10. ans=max(ans,dp[up-i]+cur);
    11. }
    12. return;
    13. }
    14. int mid=(l+r)/2;
    15. vector<int>tmp(1005,0);
    16. for(int i=0;i<=up;++i){
    17. tmp[i]=dp[i];
    18. }
    19. for(int i=mid+1;i<=r;++i){
    20. for(int j=up;j>=sz[i];--j){
    21. dp[j]=max(dp[j],dp[j-sz[i]]+a[i]);
    22. }
    23. }
    24. dfs(p,l,mid);
    25. for(int i=0;i<=up;++i){
    26. dp[i]=tmp[i];
    27. }
    28. for(int i=l;i<=mid;++i){
    29. for(int j=up;j>=sz[i];--j){
    30. dp[j]=max(dp[j],dp[j-sz[i]]+a[i]);
    31. }
    32. }
    33. dfs(p,mid+1,r);
    34. }
    35. int brilliantSurprise(vectorint>>& p, int lim) {
    36. ans=0;
    37. up=lim;
    38. int n=p.size();
    39. for(int i=0;i
    40. a[i]=accumulate(p[i].begin(),p[i].end(),0);
    41. sz[i]=p[i].size();
    42. }
    43. memset(dp,0,sizeof dp);
    44. dfs(p,0,n-1);
    45. return ans;
    46. }
    47. };

  • 相关阅读:
    centos yum安装tomcat
    数字信号处理-8-自相关
    vue中全局修改elementui,message修改时长
    不用Swagger,那我用啥?
    Redis主从复制
    如何理解JavaScript定时器的4种写法-附带面试题讲解
    IDEA中使用注解Test
    ChatGPT Prompting开发实战(十一)
    Win7安装VMware
    【云原生 | Kubernetes 实战】04、k8s 名称空间和资源配额
  • 原文地址:https://blog.csdn.net/Code92007/article/details/127484363