bzoj 1042: [HAOI2008]硬币购物

1042: [HAOI2008]硬币购物

Time Limit: 10 Sec  Memory Limit: 162 MB

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

HINT

 

Source

如果用裸的有限背包做,那么时间复杂度就上天了;

我们可以把它先当做无限背包预处理出来;

那么di个硬币的方案数就是 dp[s]-dp[s-(di+1)*ci];

如果有多个限制的硬币,那么会有重复;

运用容斥原理,只有4个数,暴力求解即可;

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define N 100000
using namespace std;

int c[5],tot,s,d[5];
long long dp[N+8],num,res;

void dfs(int u,int flag,int sum){
    if(sum<0) return;
    if(u==5){
        if(flag&1){
            res-=dp[sum];
        }else{
            res+=dp[sum];
        }
        return;
    }
    dfs(u+1,flag+1,sum-(d[u]+1)*c[u]);
    dfs(u+1,flag,sum);
}

int main(){
    memset(dp,0,sizeof(dp));
    scanf("%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&tot);
    dp[0]=1;
    for(int i=1;i<=4;i++)
        for(int j=c[i];j<=N;j++)
            dp[j]+=dp[j-c[i]];
    for(int i=1;i<=tot;i++){
        scanf("%d%d%d%d%d",&d[1],&d[2],&d[3],&d[4],&s);
        res=0;
        num=s;
        dfs(1,0,num);
        printf("%lld\n",res);
    }
}

 

posted @ 2017-09-27 16:42  JSC!  阅读(159)  评论(0编辑  收藏  举报