BZOJ 1042 HAOI2008 背包+容斥原理

题目大意:给定4种硬币的面值,多次询问这个限定这四种硬币的个数时达到某一价值的方案数

十分巧妙的一个题……蒟蒻表示打死也想不到容斥原理0.0

首先先求出不限定硬币的方案数 然后利用容斥原理

ans=不限定硬币的方案数-(硬币1超出的方案数+硬币2超出的方案数+硬币3超出的方案数+硬币4超出的方案数)+(硬币1和硬币2都超出的方案数+……)-(硬币123都超出的方案数+……)+四种硬币都超出的方案数

超出的方案数怎么求呢?比如说我们想要硬币1超出,那么我们需要有至少d1+1个硬币1 剩余的价值是s-(d1+1)*c1 方案数就是f[s-(d1+1)*c1]

太巧妙了0.0 OTZ OTZ OTZ OTZ OTZ OTZ

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
typedef long long ll;
int n,s,c[5],d[5];
ll f[M],ans;
inline ll Get_Scheme(int A=0,int B=0,int C=0,int D=0)
{
	int sum = (d[A]+1)*c[A] + (d[B]+1)*c[B] + (d[C]+1)*c[C] + (d[D]+1)*c[D] ;
	if(sum>s)
		return 0;
	return f[s-sum];
}
int main()
{
	int i,j;
	for(j=1;j<=4;j++)
		cin>>c[j];
	cin>>n;
	f[0]=1;
	for(j=1;j<=4;j++)
		for(i=c[j];i<M;i++)
			f[i]+=f[i-c[j]];
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=4;j++)
			scanf("%d",&d[j]);
		scanf("%d",&s);
		ans =Get_Scheme();
		ans-=Get_Scheme(1);
		ans-=Get_Scheme(2);
		ans-=Get_Scheme(3);
		ans-=Get_Scheme(4);
		ans+=Get_Scheme(1,2);
		ans+=Get_Scheme(1,3);
		ans+=Get_Scheme(1,4);
		ans+=Get_Scheme(2,3);
		ans+=Get_Scheme(2,4);
		ans+=Get_Scheme(3,4);
		ans-=Get_Scheme(1,2,3);
		ans-=Get_Scheme(1,2,4);
		ans-=Get_Scheme(1,3,4);
		ans-=Get_Scheme(2,3,4);
		ans+=Get_Scheme(1,2,3,4);
		printf("%lld\n",ans);
	}
}
时间: 2024-07-31 00:25:08

BZOJ 1042 HAOI2008 背包+容斥原理的相关文章

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

题目链接 1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1706  Solved: 985[Submit][Status][Discuss] Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3

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

题目链接:BZOJ - 1042 题目分析 首先 Orz Hzwer ,代码题解都是看的他的 blog. 这道题首先使用DP预处理,先求出,在不考虑每种硬币个数的限制的情况下,每个钱数有多少种拼凑方案. 为了避免重复的方案被转移,所以我们以硬币种类为第一层循环,这样阶段性的增加硬币. 一定要注意这个第一层循环要是硬币种类,并且初始 f[0] = 1. f[0] = 1; for (int i = 1; i <= 4; ++i) { for (int j = B[i]; j <= MaxS; +

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

http://www.lydsy.com/JudgeOnline/problem.php?id=1042 题意: 思路: 如果不考虑硬币个数的话,这就是一道完全完全背包的题目. 直接求的话行不通,于是这里要用容斥原理来做. 简单来说,ans=一种没超-一种硬币超+两种硬币超-三种硬币超+四种硬币超. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio>

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

题意:链接 方法:容斥原理 解析:简单题,不掉坑都对不起我自己 这题很好想的一个容斥原理,因为一共只有四种硬币,我们不方便计算满足题中要求的方案数,但是从反向思考,我们需要做的就是减掉奇数个硬币用超额的情况,然后加上偶数个硬币用超额的情况就是最终的答案(当然状态是0000的时候看做是一个基准). 然后我没什么说的了,只是有一些细节需要注意下: 1.要用long long 2.完全背包千万不要傻到每次重新背,直接一次预处理就好,不过我为什么要重新背啊!(差了8s) 代码: #include <cs

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

当然是容斥啦. 用dp预处理出\( f[i] \),表示在\( i \)价格时不考虑限制的方案数,转移方程是\( f[i]+=f[i-c[j]] \),用状压枚举不满足的状态容斥一下即可. #include<iostream> #include<cstdio> using namespace std; const long long N=100005; long long c[10],T,d[10],s,f[N],ans; long long read() { long long

[BZOJ 1042] 硬币购物 容斥原理

题意 有四种货币, 它们的价值分别是 c[0], c[1], c[2], c[3] . n 次询问, 每次给定 d[0], d[1], d[2], d[3], s, 问凑出 s , 且第 i 种货币不超过 c[i] 个的方案数. c[i], d[i], s <= 100000 , n <= 1000 . 分析 设第 i 种货币取了 x[i] 个. 问题转化为求不定方程 c[0]x[0] + c[1]x[1] + c[2]x[2] + c[3]x[3] = s 的非负整数解的个数. 且满足 4

bzoj 1042 HAOI2008 硬币购物

这道题思路是在是神. 先dp出没有限制时候的方案数. dp的时候注意 先循环 1..4 再循环 1..maxs 防止重复.边界是f[0] = 1. 这么基础的背包都忘记了=_= 接下来处理有重复的问题,容斥原理     容斥原理说起来很简单,但有一些很神奇的应用,比如这道题. 最终的答案 = 没有限制的方案 - 其中一种超了限制的方案 + 其中两种超了限制的方案 - 三种超了限制的方案 + 四种超了限制的方案 ans = f[s] + f[s - c[i]*(d[i]+1)]  - ……  +

BZOJ 1042 硬币购物(完全背包+DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1042 题意:给出四种面值的硬币c1,c2,c3,c4.n个询问.每次询问用d1.d2.d3.d4个相应的硬币能够拼出多少种总和为s? 思路:(1)首先,用完全背包求出f[i]表示四种硬币的数量无限制拼出i的方案数. (2)接着我们来理解 x=f[s]-f[s-(d1+1)*c1]的含义:x表示c1硬币的数量不超过d1个而其他三种硬币的数量不限制拼成s的方案数.我们举着例子来说明, 假设

【BZOJ 1042】 [HAOI2008]硬币购物

1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1175  Solved: 697 [Submit][Status] Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s Output