# BZOJ1042 [HAOI2008]硬币购物 【完全背包 + 容斥】

## 1042: [HAOI2008]硬币购物

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2924  Solved: 1802
[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

每次的方法数

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

## Sample Output

4
27

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
LL out = 0,flag = 1;char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
return out * flag;
}
LL f[maxn],C[5],d[5],S;
void cal(){
f[0] = 1;
for (int i = 1; i <= 4; i++)
for (int j = C[i]; j <= 100000; j++)
f[j] += f[j - C[i]];
}
int main()
{
cal();
LL ans,flag,sum;
while (T--){
ans = f[S];
for (int s = (1 << 4) - 1; s > 0; s--){
sum = 0; flag = 1;
for (int i = 1; i <= 4; i++)
if ((1 << i - 1) & s){
sum += (d[i] + 1) * C[i];
flag = -flag;
}
if (sum <= S) ans += flag * f[S - sum];
}
printf("%lld\n",ans);
}
return 0;
}


posted @ 2017-12-03 09:17  Mychael  阅读(72)  评论(0编辑  收藏