zoukankan      html  css  js  c++  java
  • [HAOI 2008]硬币购物

    Description

      硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。

    Input

      第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000

    Output

      每次的方法数

    Sample Input

    1 2 5 10 2
    3 2 3 1 10
    1000 2 2 2 900

    Sample Output

    4
    27

    题解

    显然直接用多重背包做会超时,先不考虑每种硬币数量的限制,设$f[i]$为不考虑每种硬币数量的限制时,面值为$i$的方案数,则状态转移方程就呼之欲出了:$f[i]={sum f[i-c[k]]}$,$i-c[k]>=0$,$1<=k<=4$

    为避免方案重复,要以$k$为阶段递推,边界条件为$f[0]=1$,这样预处理的时间复杂度就是$O(s)$。

    接下来对于每次询问,根据容斥原理,答案即为得到面值为$S$的不超过限制的方案数=得到面值$S$的无限制的方案数即$f[s]$

    – 第$1$种硬币超过限制的方案数 – 第$2$种硬币超过限制的方案数 – 第$3$种硬币超过限制的方案数 – 第$4$种硬币超过限制的方案数

    + 第$1$,$2$种硬币同时超过限制的方案数 + 第$1$,$3$种硬币同时超过限制的方案数 + …… + 第$1$,$2$,$3$,$4$种硬币全部同时超过限制的方案数。

    用$dfs$实现,当选择的个数是奇数时用减号否则用加号。

    当第$1$种硬币超过限制时,只要要用到$D[1]+1$枚硬币,剩余的硬币可以任意分配,所以方案数为 $F[ S – (D[1]+1)*C[1] ]$,

    当且仅当$(S – (D[1]+1)*C[1])>=0$,否则方案数为$0$。其余情况类似,每次询问只用问$16$次,所以询问的时间复杂度为$O(1)$。

     1 //It is made by Awson on 2017.9.24
     2 #include <set>
     3 #include <map>
     4 #include <cmath>
     5 #include <ctime>
     6 #include <queue>
     7 #include <stack>
     8 #include <vector>
     9 #include <string>
    10 #include <cstdio>
    11 #include <cstdlib>
    12 #include <cstring>
    13 #include <iostream>
    14 #include <algorithm>
    15 #define LL long long
    16 #define Min(a, b) ((a) < (b) ? (a) : (b))
    17 #define Max(a, b) ((a) > (b) ? (a) : (b))
    18 #define lowbit(x) ((x)&(-(x)))
    19 using namespace std;
    20 const LL N = 100000;
    21 LL Read() {
    22     char ch = getchar();
    23     LL sum = 0;
    24     while (ch < '0' || ch > '9') ch = getchar();
    25     while (ch >= '0' && ch <= '9') sum = (sum<<3)+(sum<<1)+ch-48, ch = getchar();
    26     return sum;
    27 }
    28 LL c[4], k;
    29 LL f[N+5];
    30 LL d[4], s;
    31 LL ans;
    32 
    33 void dfs(int cen, LL cnt, bool mark) {
    34     if (cnt < 0) return;
    35     if (cen == 4) {
    36         if (mark) ans -= f[cnt];
    37         else ans += f[cnt];
    38         return;
    39     }
    40     dfs(cen+1, cnt-c[cen]*(d[cen]+1), !mark);
    41     dfs(cen+1, cnt, mark);
    42 }
    43 
    44 void work() {
    45     f[0] = 1;
    46     for (int i = 0; i < 4; i++) {
    47         c[i] = Read();
    48         for (int j = c[i]; j <= N; j++)
    49             f[j] += f[j-c[i]];
    50     }
    51     k = Read();
    52     while (k--) {
    53         for (int i = 0; i < 4; i++)
    54             d[i] = Read();
    55         s = Read();
    56         ans = 0;
    57         dfs(0, s, 0);    
    58         printf("%lld
    ", ans);
    59     }
    60 }
    61 int main() {
    62     work();
    63     return 0;
    64 }
  • 相关阅读:
    September 29th 2017 Week 39th Friday
    September 28th 2017 Week 39th Thursday
    September 27th 2017 Week 39th Wednesday
    September 26th 2017 Week 39th Tuesday
    September 25th 2017 Week 39th Monday
    September 24th 2017 Week 39th Sunday
    angular2 学习笔记 ( Form 表单 )
    angular2 学习笔记 ( Component 组件)
    angular2 学习笔记 ( Http 请求)
    angular2 学习笔记 ( Router 路由 )
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7588590.html
Copyright © 2011-2022 走看看