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;    
    }
  • 相关阅读:
    uva 408 Uniform Generator
    Java实现 蓝桥杯VIP 算法提高 栅格打印问题
    Java实现 蓝桥杯VIP 算法提高 栅格打印问题
    Java实现 蓝桥杯VIP 算法提高 栅格打印问题
    Java实现 蓝桥杯VIP 算法提高 打水问题
    Java实现 蓝桥杯VIP 算法提高 打水问题
    Java实现 蓝桥杯VIP 算法提高 打水问题
    Java实现 蓝桥杯VIP 算法提高 打水问题
    Java实现 蓝桥杯VIP 算法提高 不同单词个数统计
    Java实现 蓝桥杯VIP 算法提高 不同单词个数统计
  • 原文地址:https://www.cnblogs.com/evenbao/p/9196349.html
Copyright © 2011-2022 走看看