zoukankan      html  css  js  c++  java
  • UVA 11259 Coin Changing Again

    题意:有4种硬币,面值分别为c1,c2,c3,c4,然后给出Q组查询。每组查询给出5个数d1,d2,d3,d4,v,分别表示面值为ci的硬币共有di个,然后要求将其凑成总值为v的方案数。

    数据范围大致是c<=1000,Q<=100,d,v<=100000。

    如果按照普通分组背包的做法,对每组Q都做一遍DP,那么这个复杂度就会达到10^9的级别,肯定会TLE。我也拿不出太好的办法,觉得这题DP不出来。

    其实,这题不完全是DP,我觉得这个题目的核心是容斥原理。对于每组查询,算法的复杂度基本上是O(1)这样的常数级的。

    在UVA的论坛里看到了大牛的解释:

    假设现在只有两种硬币,我们令N=所有凑出v总值的方案数,N1=第一种面值为c1的硬币取了超过d1次凑出总值v的方案数,N2=第二种面值为c2的硬币取了超过d2次凑出总值v的方案数,N12=第一种面值为c1的硬币取了超过d1次且N第二种面值为c2的硬币取了超过d2次凑出总值v的方案数。那么对于一组查询d1,d2,v,合法的方案数就是N-N1-N2+N12.

    为了计算这些N,我们利用c1,c2,c3,c4先做一遍背包容量为100000的无限背包,用dp数组记录方案数。

    那么计算N的话,直接算用dp[v]就可以了。

    怎么计算N1呢?因为c1硬币取了超过了d1次,那么我们就假设它取了d1+1次,共取走了(d1+1)*c1价值的硬币,那么方案数就是dp[v-(d1+1)*c1]。

    同理,N2的方案数就是dp[v-(d2+1)*c2],N12的方案数就是dp[v-(d1+1)*c1-(d2+1)*c2]。然后统计N-N1-N2+N12,就可以得到答案了。

    现在问题中的硬币种类边成了4个,还是用一样的原理,这时候答案就是N-N1-N2-N3-N4+N12+N13+N14+N23+N24+N34-N123-N124-N134-N234+N1234,一共16项。

     1 #include <cstdio>
     2 typedef long long LL;
     3 LL dp[100010];
     4 
     5 int main(){
     6     int c[4],d[4],v,Q,kase;
     7     scanf("%d",&kase);
     8     while(kase--){
     9         dp[0] = 1;
    10         for(int i = 1;i <= 100000;i++)  dp[i] = 0;
    11 
    12         for(int i = 0;i < 4;i++)
    13             scanf("%d",&c[i]);
    14 
    15         for(int i = 0;i < 4;i++)
    16             for(int j = c[i];j <= 100000;j++)
    17                 dp[j] += dp[j-c[i]];
    18 
    19         scanf("%d",&Q);
    20 
    21         while(Q--){
    22             LL ans = 0;
    23 
    24             for(int i = 0;i < 4;i++)
    25                 scanf("%d",&d[i]);
    26 
    27             scanf("%d",&v);
    28 
    29             for(int i = 0;i < 16;i++){
    30                 int tmp = v;
    31                 int flag = 1;
    32                 for(int j = 0;j < 4;j++){
    33                     if(i&(1<<j)){
    34                         flag = -flag;
    35                         tmp -= (d[j]+1) * c[j];
    36                     }
    37                 }
    38                 if(tmp >= 0)    ans += flag * dp[tmp];
    39             }
    40 
    41             printf("%lld
    ",ans);
    42         }
    43     }
    44     return 0;
    45 }
    View Code
  • 相关阅读:
    BZOJ-1625 宝石手镯 01背包(傻逼题)
    BZOJ-2929 洞穴攀岩 最大流Dinic(傻逼题)
    BZOJ3252: 攻略 可并堆
    二逼平衡树 Tyvj 1730 BZOJ3196 Loj#106
    [Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086
    [NOIP2014]飞扬的小鸟 D1 T3 loj2500 洛谷P1941
    BZOJ4554: [Tjoi2016&Heoi2016]游戏 luoguP2825 loj2057
    BZOJ 2599: [IOI2011]Race 点分治
    POJ1038 Bugs Integrated, Inc 状压DP+优化
    JLOI2015 城池攻占
  • 原文地址:https://www.cnblogs.com/zhexipinnong/p/3420455.html
Copyright © 2011-2022 走看看