zoukankan      html  css  js  c++  java
  • bzoj 1042

    典型的背包+容斥

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

    接下来,如果有个数的限制,那么我们就要利用一些容斥的思想:没有1个超过限制的方案=至少0个超过限制-至少1个超过限制+至少2个超过限制-至少3个超过限制+至少4个超过限制

    所以我们用2进制数枚举谁超过了限制,然后加入上面的容斥即可

    其中:如果第i种硬币的限制为ni,那么如果i要求超过限制,那么至少要用ni+1个,所以i超过限制的方案数为f[s-(ni+1)ci](f[s]为全方案数)

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ll long long
    using namespace std;
    ll dp[100005];
    int c[5];
    int l[5];
    int q;
    int cot(int sit)
    {
        int cnt=0;
        if(sit&1)
        {
            cnt++;
        }
        if(sit&2)
        {
            cnt++;
        }
        if(sit&4)
        {
            cnt++;
        }
        if(sit&8)
        {
            cnt++;
        }
        return cnt;
    }
    int main()
    {
        for(int i=1;i<=4;i++)
        {
            scanf("%d",&c[i]);
        }
        dp[0]=1;
        for(int j=1;j<=4;j++)
        {
            for(int i=1;i<=100000;i++)
            {
                if(i>=c[j])
                {
                    dp[i]+=dp[i-c[j]];
                }
            }
        }
        scanf("%d",&q);
        while(q--)
        {
            for(int i=1;i<=4;i++)
            {
                scanf("%d",&l[i]);
            }
            int s;
            scanf("%d",&s);
            ll ans=0;
            for(int i=0;i<16;i++)
            {
                int temp=s;
                if(cot(i)&1)
                {
                    for(int j=0;j<4;j++)
                    {
                        if((1<<j)&i)
                        {
                            temp-=(l[j+1]+1)*c[j+1];
                        }
                    }
                    if(temp<0)
                    {
                        continue;
                    }else
                    {
                        ans-=dp[temp];
                    }
                }else
                {
                    for(int j=0;j<4;j++)
                    {
                        if((1<<j)&i)
                        {
                            temp-=(l[j+1]+1)*c[j+1];
                        }
                    }
                    if(temp<0)
                    {
                        continue;
                    }else
                    {
                        ans+=dp[temp];
                    }
                }
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Druid初步学习
    跨区域的application共享问题。
    jsp系统时间和时间对比(活动结束不结束)
    Intellij Idea中运行tomcat 报內存溢出
    SpringMVC -rest风格修改删除
    Redis服务器的创建服务
    Double和double的区别
    1.Redis安装(转)
    查看Mysql执行计划
    linux查询日志命令总结
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10764144.html
Copyright © 2011-2022 走看看