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

P1450 [HAOI2008]硬币购物

时间:2020-01-05 16:03:12      阅读:57      评论:0      收藏:0      [点我收藏+]

标签:购物   lin   main   using   假设   scanf   背包   需要   ret   

题意

暴力显然是考虑n次多重背包。

考虑假如没有\(d_i\)的限制,那么这实际上就是一个普通的完全背包预处理,最后\(O(1)\)输出。

现在假设只有\(c_1\)这种硬币有限制,那么实际上我们只需要输出\(f_m-f_{m-(d_1+1)*c_1}\)就好了。因为既然\(c_1\)这种货币使用超过了限制,那么它必定使用了大于等于\(d_1+1\)次,也就是说我们先取出\(d_1+1\)\(c_1\)货币,剩下的容量随便装都是不合法的,那么不合法的方案数就是\(f_{m-(d_1+1)*c_1}\)

现在我们可能不止有一种硬币超出了限制,那么我们可以容斥一下,这样每次询问就可以\(2^4\)解决了。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int maxm=100010;
int n,m;
int c[5],d[5];
long long ans;
long long f[maxm];
void dfs(int now,int sum,int k)
{
    if(sum<0) return;
    if(now==5)
    {
        if(k&1) ans-=f[sum];
        else ans+=f[sum];
        return;
    }
    dfs(now+1,sum-(d[now]+1)*c[now],k+1);
    dfs(now+1,sum,k);
}
int main()
{
    for(int i=1;i<=4;i++) scanf("%d",&c[i]);
    scanf("%d",&n);
    f[0]=1;
    for(int i=1;i<=4;i++)
        for(int j=c[i];j<=maxm;j++) 
            f[j]+=f[j-c[i]];
    while(n--)
    {
        ans=0;
        for(int i=1;i<=4;i++) scanf("%d",&d[i]);
        scanf("%d",&m);
        dfs(1,m,0);
        printf("%lld\n",ans);
    }
    return 0;
}

P1450 [HAOI2008]硬币购物

标签:购物   lin   main   using   假设   scanf   背包   需要   ret   

原文地址:https://www.cnblogs.com/nofind/p/12152515.html

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