首页 > 代码库 > BZOJ 1042 HAOI 2008 硬币购物 容斥原理
BZOJ 1042 HAOI 2008 硬币购物 容斥原理
题目大意:给出4个硬币的价值和个数限制,求有多少种方法凑成S块钱。
思路:很巧妙的一种想法,用到了4这个非常小的数字。我们可以先不管每个硬币的个数限制,然后跑一次完全背包。之后把不符合的情况去除就行了。方法是,先减去一种硬币超限的数目,然后加上两种硬币超限的数目,然后减去三种硬币超限的数目,然后加上四种硬币超限的个数。当然代码就很丑了。。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define P(i) (c[i] * (l[i] + 1)) using namespace std; int c[5],l[5],s; int cnt; long long f[MAX],ans; int main() { for(int i = 1; i <= 4; ++i) scanf("%d",&c[i]); cin >> cnt; for(int i = 1; i <= cnt; ++i) { for(int j = 1; j <= 4; ++j) scanf("%d",&l[j]); scanf("%d",&s); memset(f,0,sizeof(f)); f[0] = 1; for(int _i = 1; _i <= 4; ++_i) for(int j = c[_i]; j <= s; ++j) f[j] += f[j - c[_i]]; ans = f[s]; for(int _i = 1; _i <= 4; ++_i) if(s - P(_i) >= 0) ans -= f[s - P(_i)]; if(s - P(1) - P(2) >= 0) ans += f[s - P(1) - P(2)]; if(s - P(2) - P(3) >= 0) ans += f[s - P(2) - P(3)]; if(s - P(3) - P(4) >= 0) ans += f[s - P(3) - P(4)]; if(s - P(2) - P(4) >= 0) ans += f[s - P(2) - P(4)]; if(s - P(1) - P(3) >= 0) ans += f[s - P(1) - P(3)]; if(s - P(1) - P(4) >= 0) ans += f[s - P(1) - P(4)]; if(s - P(1) - P(2) - P(3) >= 0) ans -= f[s - P(1) - P(2) - P(3)]; if(s - P(2) - P(3) - P(4) >= 0) ans -= f[s - P(2) - P(3) - P(4)]; if(s - P(1) - P(3) - P(4) >= 0) ans -= f[s - P(1) - P(3) - P(4)]; if(s - P(1) - P(2) - P(4) >= 0) ans -= f[s - P(1) - P(2) - P(4)]; if(s - P(1) - P(2) - P(3) - P(4) >= 0) ans += f[s - P(1) - P(2) - P(3) - P(4)]; printf("%lld\n",ans); } return 0; }
BZOJ 1042 HAOI 2008 硬币购物 容斥原理
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。