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

    Description

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

    Input

      第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000

    Output

      每次的方法数

    Sample Input

    1 2 5 10 2
    3 2 3 1 10
    1000 2 2 2 900
    

    Sample Output

    4
    27
    

    Solution

    很巧妙的思想。

    首先不考虑限制,那么做一遍完全背包就行了。

    若只有第一个货币有限制,设只能用(d)个,面值为(c),那么买(s)元钱的方案就是(f[s]-f[s-ccdot (d+1)]),其中(f[i])是完全背包的东西,即不考虑限制的方案。

    因为现在只能用(d)(c)元的钞票,那么一个比较显然的想法就是,由于所有超过(d)的方案都是不合法的,不妨用总体减去不合法的方案。

    那么扩展到所有货币都有限制也就很显然了,由于货币种类较小,直接暴力容斥就好了。

    时间复杂度(O(s+2^4cdot tot))

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 1e5+10;
    
    int c[5],tot,f[maxn],d[5];
    
    signed main() {
    	for(int i=1;i<=4;i++) read(c[i]);read(tot);
    	f[0]=1;
    	for(int i=1;i<=4;i++)
    		for(int j=0;j+c[i]<maxn;j++)
    			f[j+c[i]]+=f[j];
    	for(int w=1;w<=tot;w++) {
    		int mx,ans=0;
    		for(int i=1;i<=4;i++) read(d[i]);read(mx);
    		for(int s=0;s<(1<<4);s++) {
    			int a=mx;
    			for(int i=1;i<=4;i++)
    				if(s&(1<<(i-1))) a-=c[i]*(d[i]+1);
    			if(a<0) continue;
    			ans+=(__builtin_popcount(s)&1?-1:1)*f[a];
    		}write(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    React 组件间的通讯
    javascript 闭包详解及作用
    selenium使用技巧
    多线程
    渗透测试
    什么是Selenium Grid?如何搭建Selenium Grid?
    前端性能测试工具原理与行业常用工具简介
    后端性能测试工具原理与行业常用工具简介
    性能测试方法和应用
    软件性能与性能指标
  • 原文地址:https://www.cnblogs.com/hbyer/p/10373069.html
Copyright © 2011-2022 走看看