1042: [HAOI2008]硬币购物

1042: [HAOI2008]硬币购物

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 1534   Solved: 897
[ Submit][ Status][ Discuss]

Description

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

Input

第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s

Output

每次的方法数

Sample Input

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

Sample Output

4
27

HINT

数据规模

di,s<=100000

tot<=1000

Source


容斥原理呀!(苟蒻根本不会数学)
设f[i]为硬币数任意,凑齐i元方案数。。。
所以s元方案数 = f[s] - 使用c1超额方案数 - 使用c2超额方案数 - ... + 使用c1c2超额方案数 +...-使用c1c2c3超额方案数 - ...+使用c1c2c3c4超额方案数

#include<iostream>
#include<cstdio>
using namespace std;
 
const int maxn = 1e5 + 10;
typedef long long LL;
 
LL f[maxn],d[4],c[4],m,n,ans;
int i,j;
 
void dfs(int k,int tot,LL sum)
{
    if (n - sum < 0) return;
    if (k == 4)
    {
        if (n - sum >= 0 && tot)
        {
            if (tot & 1) ans -= f[n - sum];
            else ans += f[n - sum];
        }
        return;
    }
    dfs(k + 1,tot,sum);
    dfs(k + 1,tot + 1,sum + 1LL*(d[k] + 1) * c[k]);
}
 
int main()
{
    #ifdef YZY
        freopen("yzy.txt","r",stdin);
    #endif
     
    for (i = 0; i < 4; i++) scanf("%d",&c[i]);
    cin >> m;
    f[0] = 1;
    for (j = 0; j < 4; j++)
      for (i = c[j]; i <= 100000; i++)
          f[i] += f[i - c[j]];
    while (m--)
    {
        for (i = 0; i < 4; i++) scanf("%d",&d[i]);
        scanf("%d",&n);
        ans = 0;
        dfs(0,0,0);
        ans += f[n];
        printf("%lld\n",ans);
    }
    return 0;
}



你可能感兴趣的:(1042: [HAOI2008]硬币购物)