bzoj1042: [HAOI2008]硬币购物
1042: [HAOI2008]硬币购物
Time Limit: 10 Sec Memory Limit: 162 MBDescription
硬币购物一共有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
题解:容斥原理,首先我们可以背包得到Smax的方案数,如果numB有限制,那么不符合的方案数就是f[Smax - (numB + 1) Vb], 然后容斥一波, 容斥用搜索比较好,奇加偶减;
#include <bits/stdc++.h> using namespace std; const int M = 100005; int a[5], b[5]; long long ans, f[M]; void dfs(int dep, int x, int sum){ if(sum < 0)return; if(x == 5){ if(dep & 1) ans += f[sum]; else ans -= f[sum]; return ; } dfs(dep+1, x+1, sum - (b[x] + 1) * a[x]); dfs(dep, x+1, sum); } int main() { f[0] = 1; int tot; scanf("%d%d%d%d%d",&a[1], &a[2], &a[3], &a[4], &tot); for(int j = 1; j <= 4; j++) for(int i = 1; i <= M; i++) if(i - a[j] >= 0) f[i] += f[i - a[j]]; //for(int i = 1; i <= 1005; i++)printf("%I64d ", f[i]); while(tot--){ int s; scanf("%d%d%d%d%d", &b[1], &b[2], &b[3], &b[4], &s); ans = 0; dfs(1, 1, s); printf("%lld\n", ans); } }