zoukankan      html  css  js  c++  java
  • 【HAOI 2008】 硬币购物

    【题目链接】

              点击打开链接

    【算法】

              此题是一道好题!

              首先,我们发现 : 付款方法数 = 不受限制的方法数 - 受限制的方法数

              那么,我们怎么求呢?

              我们用dp求出不受限制的方法数(f[i]表示买i元的东西,不受硬币限制,有多少种方案),只需用01背包的

              方法就可以了,实现非常简单

              那么受限制的方法数怎么求呢?由容斥原理可知,受限制的方法数 = 第一种硬币超限 + 第二种硬币超限 + ... 

              - 第一,二,三,四种硬币超限

              第一种硬币超限,其实就是先选(d1 + 1)枚第一种硬币,其他随便选,那么对应的数量就是

              f[s - (d1 + 1) * c[1]],其他情况类似,注意当减下来小于零时是不可以的

              于是,这道题便迎刃而解了!

      【代码】

               

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXS 100010
    
    long long i,j,d1,d2,d3,d4,T,s;
    long long c[5];
    long long ans;
    long long f[MAXS];
    
    int main() 
    {
            
            scanf("%lld%lld%lld%lld%lld",&c[1],&c[2],&c[3],&c[4],&T);
            f[0] = 1;
            for (i = 1; i <= 4; i++) 
            {
                    for (j = c[i]; j < MAXS; j++) 
                    {
                            f[j] += f[j-c[i]];
                    }
            }
            while (T--) 
            {
                    scanf("%lld%lld%lld%lld%lld",&d1,&d2,&d3,&d4,&s);
                    ans = f[s];
                    if (s - (d1 + 1) * c[1] >= 0) ans -= f[s - (d1 + 1) * c[1]];
                    if (s - (d2 + 1) * c[2] >= 0) ans -= f[s - (d2 + 1) * c[2]];
                    if (s - (d3 + 1) * c[3] >= 0) ans -= f[s - (d3 + 1) * c[3]];
                    if (s - (d4 + 1) * c[4] >= 0) ans -= f[s - (d4 + 1) * c[4]];
                    if (s - (d1 + 1) * c[1] - (d2 + 1) * c[2] >= 0) ans += f[s - (d1 + 1) * c[1] - (d2 + 1) * c[2]];
                    if (s - (d1 + 1) * c[1] - (d3 + 1) * c[3] >= 0) ans += f[s - (d1 + 1) * c[1] - (d3 + 1) * c[3]];
                    if (s - (d1 + 1) * c[1] - (d4 + 1) * c[4] >= 0) ans += f[s - (d1 + 1) * c[1] - (d4 + 1) * c[4]];
                    if (s - (d2 + 1) * c[2] - (d3 + 1) * c[3] >= 0) ans += f[s - (d2 + 1) * c[2] - (d3 + 1) * c[3]];
                    if (s - (d2 + 1) * c[2] - (d4 + 1) * c[4] >= 0) ans += f[s - (d2 + 1) * c[2] - (d4 + 1) * c[4]];
                    if (s - (d3 + 1) * c[3] - (d4 + 1) * c[4] >= 0) ans += f[s - (d3 + 1) * c[3] - (d4 + 1) * c[4]];
                    if (s - (d1 + 1) * c[1] - (d2 + 1) * c[2] - (d3 + 1) * c[3] >= 0) ans -= f[s - (d1 + 1) * c[1] - (d2 + 1) * c[2] - (d3 + 1) * c[3]];
                    if (s - (d1 + 1) * c[1] - (d2 + 1) * c[2] - (d4 + 1) * c[4] >= 0) ans -= f[s - (d1 + 1) * c[1] - (d2 + 1) * c[2] - (d4 + 1) * c[4]];
                    if (s - (d1 + 1) * c[1] - (d3 + 1) * c[3] - (d4 + 1) * c[4] >= 0) ans -= f[s - (d1 + 1) * c[1] - (d3 + 1) * c[3] - (d4 + 1) * c[4]];
                    if (s - (d2 + 1) * c[2] - (d3 + 1) * c[3] - (d4 + 1) * c[4] >= 0) ans -= f[s - (d2 + 1) * c[2] - (d3 + 1) * c[3] - (d4 + 1) * c[4]];
                    if (s - (d1 + 1) * c[1] - (d2 + 1) * c[2] - (d3 + 1) * c[3] - (d4 + 1) * c[4] >= 0) ans += f[s - (d1 + 1) * c[1] - (d2 + 1) * c[2] - (d3 + 1) * c[3] - (d4 + 1) * c[4]];
                    printf("%lld
    ",ans);    
            } 
        
            return 0;    
    }
  • 相关阅读:
    二叉树专题
    强化学习的几个基本概念
    LeetCode #111 二叉树的最小深度
    NC127 最长公共子串
    快速排序
    NC78 反转链表
    《合作的进化》读后总结
    Optional和Stream的map与flatMap
    最爱的小工具,谁用谁知道!
    SpringBoot应用启动过程分析
  • 原文地址:https://www.cnblogs.com/evenbao/p/9196349.html
Copyright © 2011-2022 走看看