bzoj1042 [HAOI2008]硬币购物
1042: [HAOI2008]硬币购物
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2648 Solved: 1609
[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
分析:可以用背包来做,但是会超时,可以考虑容斥原理。题目要我们求满足所有条件的方案数,那么我们可以用第二条容斥原理,即所有方案数-不满足一条的方案数+不满足两条的方案数-不满足三条的方案数......,可以利用dfs解决。如果第i个硬币不满足条件,则这个硬币用d[i]+1个,统计一下就好了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; long long c[5], tot,d[5],s,ans,f[100010]; void dfs(int cnt, long long n,int k) { if (cnt == 5) { ans += f[n] * k; return; } if (c[cnt] * (d[cnt] + 1) <= n) dfs(cnt + 1, n - c[cnt] * (d[cnt] + 1), -k); dfs(cnt + 1, n, k); } int main() { scanf("%lld%lld%lld%lld%lld", &c[1], &c[2], &c[3], &c[4], &tot); f[0] = 1; for (int i = 1; i <= 4; i++) for (int j = c[i]; j <= 100000; j++) f[j] += f[j - c[i]]; while (tot--) { ans = 0; scanf("%lld%lld%lld%lld%lld", &d[1], &d[2], &d[3], &d[4], &s); dfs(1,s,1); printf("%lld\n", ans); } return 0; }