• 洛谷P1450 [HAOI2008]硬币购物(有个数限制的多重背包 完全背包+容斥/完全背包+回滚背包)


    题目

    共有 4 种硬币,面值分别为 c1​,c2​,c3​,c4​。

    某人去商店买东西,去了 n 次。

    对于每次购买,他带了 di​ 枚 i 种硬币,想购买 s 的价值的东西。

    请问每次有多少种付款方法。

    数据范围:1<=ci,di,s<=1e5,n<=1000

    思路来源

    洛谷题解

    题解1(完全背包+容斥)

    有个数限制的背包=没有个数限制的背包+容斥超限部分

    只有4种数,可以枚举哪些是超过数量上限的

    先用不限制次数的做完全背包,然后枚举超过数量上限的集合做容斥

    容斥某个集合时,先将一定会引起超限的量取出来,

    这样剩下的任意取也会超限,统计与其对应的超限的方案

    复杂度:O(2^4*4*max(s)+4*n)

    题解2(完全背包+回滚背包

    有个数限制的背包=没有个数限制的背包+撤销超限的转移

    没有个数限制的背包即完全背包,先做完全背包

    有了di的限制之后,考虑把来自>di的转移给撤销掉,回答完询问之后再加回来

    完全背包本质上是对若干个位置做了dp的前缀和,而有个数限制时,相当于前缀和作差

    复杂度:O(4*n*max(s))

    量级上比较极限,但是因为背包转移常数较小,所以可以通过

    代码1

    1. #include
    2. using namespace std;
    3. const int N=1e5+10;
    4. typedef long long ll;
    5. int c[4],d[4],s,n;
    6. ll dp[N];
    7. int main(){
    8. dp[0]=1;
    9. for(int i=0;i<4;++i){
    10. scanf("%d",&c[i]);
    11. for(int j=c[i];j
    12. dp[j]+=dp[j-c[i]];
    13. }
    14. }
    15. scanf("%d",&n);
    16. while(n--){
    17. for(int i=0;i<4;++i){
    18. scanf("%d",&d[i]);
    19. }
    20. scanf("%d",&s);
    21. int up=1<<4;
    22. ll ans=0;
    23. for(int i=0;i
    24. int cnt=0,now=s;
    25. for(int j=0;j<4;++j){
    26. if(i>>j&1){
    27. cnt++;
    28. now-=c[j]*(d[j]+1);
    29. }
    30. }
    31. if(now<0)continue;
    32. if(cnt&1)ans-=dp[now];
    33. else ans+=dp[now];
    34. }
    35. printf("%lld\n",ans);
    36. }
    37. return 0;
    38. }

    代码2

    1. #include
    2. using namespace std;
    3. const int N=1e5+10;
    4. typedef long long ll;
    5. int c[4],d[4],s,n;
    6. ll dp[N];
    7. int main(){
    8. dp[0]=1;
    9. for(int i=0;i<4;++i){
    10. scanf("%d",&c[i]);
    11. for(int j=c[i];j
    12. dp[j]+=dp[j-c[i]];
    13. }
    14. }
    15. scanf("%d",&n);
    16. while(n--){
    17. for(int i=0;i<4;++i){
    18. scanf("%d",&d[i]);
    19. int w=c[i]*(d[i]+1);
    20. for(int j=N-1;j>=w;--j){
    21. dp[j]-=dp[j-w];
    22. }
    23. }
    24. scanf("%d",&s);
    25. printf("%lld\n",dp[s]);
    26. for(int i=0;i<4;++i){
    27. int w=c[i]*(d[i]+1);
    28. for(int j=w;j
    29. dp[j]+=dp[j-w];
    30. }
    31. }
    32. }
    33. return 0;
    34. }

  • 相关阅读:
    找不到mfc140u.dll怎么办?修复缺失mfc140u.dll的多种方案分享
    fmllr--学习笔记
    9.14小米笔试C++
    服务端Skynet(二)——消息调度机制
    【华为OD机试真题 python】 太阳能板最大面积【2022 Q4 | 100分】
    MySQL (十四) 两阶段提交
    ECC加密算法的数学原理
    《C++标准库第2版》3.2 虽旧犹新的语言特性 笔记
    【Token】JWT使用Token进行登录
    操作系统导论--受限制的直接执行
  • 原文地址:https://blog.csdn.net/Code92007/article/details/105999966