zoukankan      html  css  js  c++  java
  • ●BZOJ 1042 [HAOI2008]硬币购物

    题链:

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

    题解:

    容斥原理,dp预处理
    首先跑个无限物品的背包dp求出dp[i]表示在四种物品都有无限个情况下有多少种方法支付 i元。
    然后对于每个询问,答案就是 dp[S]-不合法的方法。
    那么这个不合法的方法数怎么求呢?
    举个例子:如果 c1不能超过d1个的话,那么我们就强制用掉 d1+1个 c1硬币,
    那么dp[S-(d1+1)*c1]就是c1不合法的方法数。

    所以这样就可以类似的求出其它硬币的不合法的方法数,以及某几种硬币都不合法的方法数,用于容斥计算。
    即 ANS=dp[S] - 一种硬币不合法 + 两种硬币不合法 -三种硬币不合法 +四种硬币不合法。
    DFS实现

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define MAXN 105000
    #define ll long long
    #define filein(x) freopen(#x".in","r",stdin);
    #define fileout(x) freopen(#x".out","w",stdout);
    using namespace std;
    ll dp[MAXN],c[10],d[10];
    ll tot,ANS,S;
    void dfs(int p,int num,ll de){
    	if(p==5) return;
    	ll nde=de+(d[p]+1)*c[p];
    	ll val=S-nde<0?0:dp[S-nde];
    	ANS+=val*(((num+1)&1)?-1:1);
    	dfs(p+1,num+1,nde);
    	dfs(p+1,num,de);
    }
    int main()
    {
    	dp[0]=1;
    	for(int i=1;i<=4;i++) {
    		scanf("%lld",&c[i]);
    		for(int j=c[i];j<=100000;j++)
    			dp[j]+=dp[j-c[i]];
    	}
    	scanf("%lld",&tot);
    	while(tot--){
    		for(int i=1;i<=4;i++) 
    			scanf("%lld",&d[i]);
    		scanf("%lld",&S);
    		ANS=dp[S];
    		dfs(1,0,0);
    		printf("%lld
    ",ANS);
    	}
    	return 0;
    }
    

  • 相关阅读:
    日志配置
    Mybaties核心配置文件
    配置3
    写了两个数据获得方式----费劲周折
    applicationContext
    配置2
    Django-缓存的配置
    RabbitMQ的工作模式
    centos下保留python2安装python3
    python位运算
  • 原文地址:https://www.cnblogs.com/zj75211/p/8029358.html
Copyright © 2011-2022 走看看