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. CSV 读写

    using System; using System.IO; using System.Runtime.InteropServices; using UnityEngine; public class ...

  2. HDU 5312(数学推导+技巧)

    首先说一下.N*(N-1)/2为三角形数,随意一个自然数都最多可由三个三角形数表示. 对于,对于给定的要求值 V, 那么其一组解可表示为 V = 6*(K个三角形数的和)+K: 即随意由k个数组成的解 ...

  3. 【Linux】less命令

    用途 less主要用于查看档案内容,与more的功能一致,但是比more更强大 全称 less的全称就为less 说明 空格键 :代表向下翻一页 pagedown : 代表向下翻一页 pageup:向 ...

  4. JDBC JdbTemplate&NamedParameterJdbcTemplate(Spring工具类)

    使用该工具类需要从spring开发包中导入spring.jar和commons-logging.jar,这个模板是线程安全的.   JdbcTemplate: public class JdbcTem ...

  5. Android WiFi热点7.1以上版本适配

    代码地址如下:http://www.demodashi.com/demo/13907.html 一.准备工作 开发环境:  jdk1.8  AS(3.0.1) 运行环境:  华为V10(Android ...

  6. Linux命令-权限管理命令:chgrp

    groupadd shuaige 创建一个用户组名字叫shuaige ls -l /home/wangyunpeng/abcd 查看abcd文件的权限 chgrp shuaige /home/wang ...

  7. spring 3.0系统集成webservice

    spring 3.0系统集成webservice,踩了很多坑以后总算成功了,故写下这篇博客以记录. 1.准备jar包 由于项目是spring3.0,所以应该要使用cxf 2.7版本才可以成功配置,高版 ...

  8. 【Arduino】超声波模块(HC-SR04)

    还好,这个模块有现成的库能够用: https://github.com/bosgood/arduino-playground/tree/master/lib/HCSR04Ultrasonic 下面仅仅 ...

  9. 简单的并发测试工具 ab.exe ab.zip可下载 -摘自网络

    ab.exe是一个性能检测工具,是apache server中的一个小组件,使用简单,方便    下载地址:http://files.cnblogs.com/files/gossip/ab.zip   ...

  10. Object-C中的字符串对象1-不可变字符串

    #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { ...