1042: [HAOI2008]硬币购物
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2953 Solved: 1822
[ 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
3 2 3 1 10
1000 2 2 2 900
Sample Output
4
27
27
HINT
Source
思路:很巧妙的题目,一般我们是直接完全背包那样求方案数的,但是这样会超时,考虑到硬币种类不多,应该先算出不限硬币数目的方案数,再利用容斥原理去掉非法的方案数,b[i]+1就是第i种硬币非法的状态了。
# include <iostream>
# include <cstdio>
using namespace std;
typedef long long LL;
const int maxn = 1e5;
LL dp[maxn+30]={1}, a[5], b[5], s, ans;
void dfs(int pos, LL sum, int cnt)
{
if(sum < 0) return;
if(pos == 5)
{
if(cnt&1) ans -= dp[sum];
else ans += dp[sum];
return;
}
dfs(pos+1, sum, cnt);
dfs(pos+1, sum-(b[pos]+1)*a[pos], cnt+1);
}
int main()
{
int t;
for(int i=1; i<=4; ++i) scanf("%lld",&a[i]);
for(int i=1; i<=4; ++i)
for(int j=0; j+a[i]<=maxn; ++j)
dp[j+a[i]] += dp[j];
scanf("%d",&t);
while(t--)
{
for(int i=1; i<=4; ++i) scanf("%lld",&b[i]);
scanf("%lld",&s);
ans = 0;
dfs(1, s, 0);
printf("%lld\n",ans);
}
return 0;
}