zoukankan      html  css  js  c++  java
  • [bzoj1042] [HAOI2008]硬币购物

    [bzoj1042] [HAOI2008]硬币购物

    Description

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

    Input

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

    Output

    每次的方法数

    HINT

    数据规模
    di,s<=100000
    tot<=1000

    第一眼看过去,这是一道求背包方案数的问题,这个我们大家都会求.但是题目显然不会有那么简单.第一眼数据范围感觉像是(O(N))的,对于每次询问(O(1))出解,这样感觉差不多.好了,我们的思路回到如何如何预处理上去.由于C1,C2,C3,C4是提前告诉你了的,但由于D1,D2,D3,D4,s没有告诉你.所以我们无法根据询问处理出答案.但是我们能处理出没有限制的硬币数情况下的方案总数.所以我们考虑由非限制硬币数的答案转移到限制的硬币数的答案.于是我们想到了容斥原理.我们算出了所有的非限制硬币数的答案,那么我们还可以算出每个硬币超限的方案数,那么我们就可以通过容斥原理来实现了.那么答案就是:总超限购买的方案数[sum]-硬币1超限购买的方案数...+硬币1和硬币2超限购买的方案数...最后我们考虑每一个硬币超限购买的方案数.假设是硬币x,我们优先用D[x]+1个硬币x,刚好超限.假设当前算到的剩余钱数是sum,那么方案就是f[sum-(D[x]+1)*C[x]].具体过程通过dfs实现方便一些.

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    
    static const int maxm=5;
    static const int size=1e6+10;
    
    int D[maxm],C[maxm];
    LL f[size];
    int T,tot;
    LL ans;
    
    void dfs(int x,int k,int sum){
    	if(sum<0)return;
    	if(x==5){
    		if(k&1)ans-=f[sum];
    		else ans+=f[sum];
    		return;
    	}
    	dfs(x+1,k,sum);
    	dfs(x+1,k+1,sum-(D[x]+1)*C[x]);
    }
    
    int main(){
    	for(int i=1;i<=4;i++)scanf("%d",&C[i]);
    	scanf("%d",&T);
    	
    	f[0]=1;
    	for(int i=1;i<=4;i++)
    		for(int v=C[i];v<=100000;v++)
    			f[v]+=f[v-C[i]];
    	
    	while(T--){
    		for(int i=1;i<=4;i++)scanf("%d",&D[i]);
    		scanf("%d",&tot);ans=0;
    		dfs(1,0,tot);
    		printf("%lld
    ",ans);
    	}
    	
    	
    	return 0;
    }
    

    传送门

  • 相关阅读:
    POJ 1328 Radar Installation
    POJ 1700 Crossing River
    POJ 1700 Crossing River
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3069 Saruman's Army(贪心)
    poj 3069 Saruman's Army(贪心)
    Redis 笔记与总结2 String 类型和 Hash 类型
    数据分析方法有哪些_数据分析方法
    数据分析方法有哪些_数据分析方法
  • 原文地址:https://www.cnblogs.com/Exbilar/p/6817775.html
Copyright © 2011-2022 走看看