码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 1042: [HAOI2008]硬币购物

时间:2018-02-03 16:18:49      阅读:145      评论:0      收藏:0      [点我收藏+]

标签:math   限制   com   ons   log   cst   span   markdown   print   

题目链接

bzoj1042

题解

如果没有个数限制就是一个完全背包
考虑利用全集减去超出限制的种数
利用容斥
减去一种金币超出的,加上两种金币超出的,减去三种.......

\(f(S)\)只有 S种金币超出的方案数,\(g(S)\)为S中的金币超过方限制,其他随意的方案数
那么\(\sum_{T\supseteq S}f \left(T \right)\)
我们要求\(f\left( \emptyset \right)\)
求g(s),吧\(N\)中减去\(S\)中选了\(d_i+1\)个的和,然后剩下的就是一个完全背包
预处理后容斥查询

code

#include<cstdio>

inline int read() {
    int x=0,f=1;
    char c=getchar() ;
    while(c<'0'||c>'9') {
         if(c=='-')f=-1;
         c=getchar();
    }
    while(c<='9'&&c>='0') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}const int maxn = 100001;
int M[6],N[6];
int f[maxn];
int tot,ned;
void init() {
    f[0]=1;
    for(int i=1;i<=4;++i)
        for(int j=M[i];j<maxn;++j) 
            f[j]+=f[j-M[i]];
}
int ans;
void solve(int rem,int cnt,int num) {
    if(num==5) {
        if(!cnt)return ;
        if(rem<0)return ;
        if(cnt&1) ans-=f[rem];
        else ans+=f[rem];
        return ;
    }
    solve(rem-((N[num]+1)*M[num]),cnt+1,num+1);
    solve(rem,cnt,num+1);
}
int main() {
    for(int i=1;i<5;++i) M[i]=read();
    tot=read();
    init();
    for(;tot--;) {
        for(int i=1;i<5;++i) N[i]=read();
        ned=read();ans=f[ned];
        solve(ans,0,1);
        printf("%d\n",ans);
    }
    return 0;
}

bzoj 1042: [HAOI2008]硬币购物

标签:math   限制   com   ons   log   cst   span   markdown   print   

原文地址:https://www.cnblogs.com/sssy/p/8408937.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!