bzoj1042 [HAOI2008]硬币购物

1042: [HAOI2008]硬币购物

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2648  Solved: 1609
[Submit][Status][Discuss]

Description

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

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
分析:可以用背包来做,但是会超时,可以考虑容斥原理。题目要我们求满足所有条件的方案数,那么我们可以用第二条容斥原理,即所有方案数-不满足一条的方案数+不满足两条的方案数-不满足三条的方案数......,可以利用dfs解决。如果第i个硬币不满足条件,则这个硬币用d[i]+1个,统计一下就好了.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

long long c[5], tot,d[5],s,ans,f[100010];

void dfs(int cnt, long long n,int k)
{
    if (cnt == 5)
    {
        ans += f[n] * k;
        return;
    }
    if (c[cnt] * (d[cnt] + 1) <= n)
    dfs(cnt + 1, n - c[cnt] * (d[cnt] + 1), -k);
    dfs(cnt + 1, n, k);
}

int main()
{
    scanf("%lld%lld%lld%lld%lld", &c[1], &c[2], &c[3], &c[4], &tot);
    f[0] = 1;
    for (int i = 1; i <= 4; i++)
        for (int j = c[i]; j <= 100000; j++)
            f[j] += f[j - c[i]];
    while (tot--)
    {
        ans = 0;
        scanf("%lld%lld%lld%lld%lld", &d[1], &d[2], &d[3], &d[4], &s);
        dfs(1,s,1);
        printf("%lld\n", ans);
    }

    return 0;
}

 

posted @ 2017-08-05 10:56  zbtrs  阅读(...)  评论(... 编辑 收藏