zoukankan      html  css  js  c++  java
  • Luogu P1450 [HAOI2008]硬币购物 背包+容斥原理

    考虑如果没有个数的限制,那么就是一个完全背包,所以先跑一个完全背包,求出没有个数限制的方案数即可。

    因为有个数的限制,所以容斥一下:没有1个超过限制的方案=至少0个超过限制-至少1个超过限制+至少2个超过限制-至少3个超过限制+至少4个超过限制

    如何求上面的方案数?有限制时,把$c[i]$这个硬币取了超过$d[i]$次是不应该有贡献的,那么我们先取出$d[i]+1$个价值为$c[i]$的硬币,然后剩下的就是$f[sum-c[i]*(d[i]+1)]$,这就是我们所不需要的答案, 把它按容斥的思路搞掉就行了。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<vector>
    #include<map>
    #include<set>
    #define ll long long
    #define R register int
    static char B[1<<15],*S=B,*D=B;
    #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin))?EOF:*S++)
    using namespace std;
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    }
    const int N=100000;
    int n,tot;
    int c[5],d[5];
    ll f[N+10];
    signed main() {
        for(R i=1;i<=4;++i) c[i]=g(); tot=g(); f[0]=1;
        for(R i=1;i<=4;++i) for(R j=c[i];j<=N;++j) f[j]+=f[j-c[i]];
        while(tot--) {
            for(R i=1;i<=4;++i) d[i]=g(); register ll sum=g(),ans=0;
            for(R i=0;i<=15;++i) { R cnt=0; register ll t=sum;
                for(R j=1;j<=4;++j) if(i&(1<<(j-1))) t-=c[j]*(d[j]+1),cnt^=1;
                if(t<0) continue; cnt?ans-=f[t]:ans+=f[t];
            } printf("%lld
    ",ans);
        }
    }

    2019.06.02

  • 相关阅读:
    内存管理3 Win32汇编语言056
    高级强制类型转换 C++快速入门37
    内存管理3 Win32汇编语言056
    密码学基础
    危险API的禁用列表
    危险API的禁用列表
    《那些年啊,那些事——一个程序员的奋斗史》——68
    《那些年啊,那些事——一个程序员的奋斗史》——68
    《那些年啊,那些事——一个程序员的奋斗史》——68
    春节期间停止更新
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10965049.html
Copyright © 2011-2022 走看看