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;
    }
    

    传送门

  • 相关阅读:
    灵活读取Configuration文件
    Web页面访问权限
    母版页(MasterPage),你真得了解了吗?
    基于对象和面向对象
    [翻译]Silverlight 3中的tooltip
    2009年自我总结
    W3C CSS Validator 更喜欢CSS文件以一个class开头而不是注释?
    【翻译】读取文本文件(txt、csv、log、tab、fixed length)(上)
    1z0062 题库解析2
    1z0062 题库解析3
  • 原文地址:https://www.cnblogs.com/Exbilar/p/6817775.html
Copyright © 2011-2022 走看看