http://www.lydsy.com/JudgeOnline/problem.php?id=1042

一开始写了个O(nv)的背包,果断tle。。。

看了题解,,好神。。用了组合数学中的多重集合方案的容斥原理。

设$A_i$表示i超过d[i]的性质

则我们要求:

$$| \overline{A_1} \cap \overline{A_2} \cap ... \cap \overline{A_n} |$$

而我们可以根据容斥求出这个值,即:

$$| \overline{A_1} \cap \overline{A_2} \cap ... \cap \overline{A_n} | = | S | - (| A_1 | + | A_1 | + ... + | A_n |) + (|A_1 \cap A_2| + |A_1 \cap A_3| + ... + |A_{n-1} \cap A_n|) - ...$$

本题中,$|S|$就是硬币有无限制的数量来放满s元钱,这个用完全背包来搞就行了。而容斥的其它部分就有些神奇。

首先处理完完全背包的数组f[i]后,我们可以观察,怎么将$A_i$算出来?假如有$d_i$个i硬币,容量是s的背包,思考为什么会多出方案?

可以发现,多出方案的情况是每一种方案里必定有$d_i+1$枚硬币,那么可以看做是,在所有容量为$s-(d_i+1)*c_i$的背包的方案添加$d_i+1$枚i硬币,这样就保证了至少有$d_i+1$枚硬币。那么可以完美得出了$A_i$。而性质$A_i$之间的交集其实就是$s-(d_i+1)*c_i-(d_j+1)*c_j-...-(d_k+1)*c_k$,这个很容易看出来吧。。

然后问题就解决了。

2015.4.19 upd:

设Ai为第i种硬币数量超过Di的性质,则问题就是求:
Ai补的交集
那么也就是容斥一下答案要求的性质就是:
全集S-(Ai)+(Ai交Aj)-...
令f[i]表示恰好花费i的完全背包方案数。
发现Ai的性质就是:已经在背包里放了至少Di+1个i物品,然后剩下的背包随便放的方案,即f[s-(Di+1)*Ci]!
然后求这些性质的交集,发现其实和上面分析一样!Ai与Aj的交集的方案就是f[s-(Di+1)*Ci-(Dj+1)*Cj]!
于是容斥一下就行了!!!

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mkpii make_pair<int, int>
#define pdi pair<double, int>
#define mkpdi make_pair<double, int>
#define pli pair<ll, int>
#define mkpli make_pair<ll, int>
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
#define printarr1(a, b) for1(_, 0, b) cout << a[_] << '\t'; cout << endl
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
inline const int max(const int &a, const int &b) { return a>b?a:b; }
inline const int min(const int &a, const int &b) { return a<b?a:b; } const int N=100005;
ll f[N], ans;
int n, c[5], d[5], s; inline void cmp(int v) { for1(i, v, s) f[i]+=f[i-v]; }
void dfs(int dep, int x, int sum) {
if(dep==5) {
if(s-sum<0) return;
if(x&1) ans-=f[s-sum];
else ans+=f[s-sum];
return;
}
dfs(dep+1, x, sum);
dfs(dep+1, x+1, sum+d[dep]);
}
int main() {
for1(i, 1, 4) read(c[i]); int tot=getint();
f[0]=1;
s=100005;
for1(i, 1, 4) cmp(c[i]);
while(tot--) {
for1(i, 1, 4) read(d[i]);
for1(i, 1, 4) d[i]=(d[i]+1)*c[i];
read(s);
ans=0;
dfs(1, 0, 0);
printf("%lld\n", ans);
}
return 0;
}

  


Description

硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。

Input

第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s

Output

每次的方法数

Sample Input

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

Sample Output

4
27

HINT

数据规模

di,s<=100000

tot<=1000

Source

 

【BZOJ】1042: [HAOI2008]硬币购物(dp+容斥原理)的更多相关文章

  1. bzoj 1042: [HAOI2008]硬币购物 dp+容斥原理

    题目链接 1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1706  Solved: 985[Submit][ ...

  2. bzoj 1042: [HAOI2008]硬币购物【容斥原理+dp】

    当然是容斥啦. 用dp预处理出\( f[i] \),表示在\( i \)价格时不考虑限制的方案数,转移方程是\( f[i]+=f[i-c[j]] \),用状压枚举不满足的状态容斥一下即可. #incl ...

  3. BZOJ 1042: [HAOI2008]硬币购物(容斥原理)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1042 题意: 思路: 如果不考虑硬币个数的话,这就是一道完全背包的题目. 直接求的话行不通,于是这里 ...

  4. Bzoj 1042: [HAOI2008]硬币购物 容斥原理,动态规划,背包dp

    1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1747  Solved: 1015[Submit][Stat ...

  5. BZOJ 1042: [HAOI2008]硬币购物( 背包dp + 容斥原理 )

    先按完全背包做一次dp, dp(x)表示x元的东西有多少种方案, 然后再容斥一下. ---------------------------------------------------------- ...

  6. BZOJ 1042: [HAOI2008]硬币购物 [容斥原理]

    1042: [HAOI2008]硬币购物 题意:4种硬币.面值分别为c1,c2,c3,c4.1000次询问每种硬币di个,凑出\(s\le 10^5\)的方案数 完全背包方案数? 询问太多了 看了题解 ...

  7. BZOJ 1042: [HAOI2008]硬币购物 容斥+背包

    1042: [HAOI2008]硬币购物 Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请 ...

  8. BZOJ 1042 [HAOI2008]硬币购物(完全背包+容斥)

    题意: 4种硬币买价值为V的商品,每种硬币有numi个,问有多少种买法 1000次询问,numi<1e5 思路: 完全背包计算出没有numi限制下的买法, 然后答案为dp[V]-(s1+s2+s ...

  9. [BZOJ 1042] [HAOI2008] 硬币购物 【DP + 容斥】

    题目链接:BZOJ - 1042 题目分析 首先 Orz Hzwer ,代码题解都是看的他的 blog. 这道题首先使用DP预处理,先求出,在不考虑每种硬币个数的限制的情况下,每个钱数有多少种拼凑方案 ...

  10. BZOJ 1042: [HAOI2008]硬币购物 容斥原理_背包_好题

    Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买s i的价值的东西.请问每次有多少种付款方法. 题解: 十分喜 ...

随机推荐

  1. vcs github gitlab git名词解释

    vcs:version control system git:一个版本管理工具,从git上clone,除了代码,还会把版本信息也给你clone下来. github:一个基于git的代码管理网站,支持公 ...

  2. ibatis/mybatis显示sql语句 log4j.properties配置文件

    将ibatis/mybatis log4j运行级别调到DEBUG可以在控制台打印出ibatis运行的sql语句,方便调试: ### 设置Logger输出级别和输出目的地 ### log4j.rootL ...

  3. Android EditText 赋值与取值

    //取值 String strSmsPhone=m_txtSmsPhone.getText().toString(); //赋值 m_txtSmsPhone.setText("你好" ...

  4. 支付宝钱包手势密码破解实战(root过的手机可直接绕过手势密码)

    /* 本文章由 莫灰灰 编写,转载请注明出处. 作者:莫灰灰    邮箱: minzhenfei@163.com */ 背景 随着移动互联网的普及以及手机屏幕越做越大等特点,在移动设备上购物.消费已是 ...

  5. 蜜果私塾:informix数据库学习合集[不断补充]

    一.infomix使用备忘录     目录结构:     1. 启动与停止命令:      2. 修改数据库编码:      3. 查看informix占用的端口:      4. 使用dbacces ...

  6. [Jobdu] 题目1139:最大子矩阵

    题目描述: 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵.比如,如下4 * 4的矩阵 0 -2 -7 09 2 -6 2-4 1 -4 ...

  7. int、char、long各占多少字节数

    Java基本类型占用的字节数:1字节: byte , boolean2字节: short , char4字节: int , float8字节: long , double 编码与中文:Unicode/ ...

  8. Nginx 使用中文URL,中文目录路径

    Nginx 使用中文URL,中文目录路径 分类: linux2012-05-03 11:04 2672人阅读 评论(0) 收藏 举报 nginxurl服务器translationcentosserve ...

  9. 每日英语:Air Pollution From Coal Use Cuts Lifespans in China, Study Shows

    Air pollution from coal combustion likely cut life expectancy in parts of China by more than five ye ...

  10. HDU 1863 畅通工程 克鲁斯卡尔算法

    畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...