bzoj1042[HAOI2008]硬币购物

来源:互联网 发布:php内核源码分析 编辑:程序博客网 时间:2024/05/16 11:21

题意就不说了,原处就说的很明白。可以明显的看出是背包问题,但多重背包问题还是有一定难度的,容斥原理与背包的应用还是第一次见,一开始并没有想到(感谢hzw)。
解法是这样的:先求出不限制硬币多少的答案数,通过容斥定理,要减去第一种硬币超过数、第二种硬币超过数、第三种硬币超过数、第四种硬币超过数,加上第一、二种硬币同时超过数、加上第一、三种硬币同时超过数、加上第一、四种硬币同时超过数、加上第二、三种硬币同时超过数、加上第二、四种硬币同时超过数、加上第三、四种硬币同时超过数………………由此类推,就将超过的都减掉了,剩下的就是答案!

恶心但好理解的for

#include<cstdio>#include<cstring>using namespace std;typedef long long LL;LL c[5],d[5],f[110000];int main(){    for(int i=1;i<=4;i++)scanf("%d",&c[i]);    memset(f,0,sizeof(f));f[0]=1;    for(int i=1;i<=4;i++)        for(int j=c[i];j<=100000;j++)            f[j]+=f[j-c[i]];    int n,s;    scanf("%d",&n);    while(n--)    {        for(int i=1;i<=4;i++)scanf("%d",&d[i]);        scanf("%d",&s);LL ans=f[s];        for(int i=1;i<=4;i++)            if(s>=(d[i]+1)*c[i])ans-=f[s-(d[i]+1)*c[i]];        for(int i=1;i<=3;i++)            for(int j=i+1;j<=4;j++)                    if(s>=((d[i]+1)*c[i]+(d[j]+1)*c[j]))                        ans+=f[s-((d[i]+1)*c[i]+(d[j]+1)*c[j])];        for(int i=1;i<=2;i++)            for(int j=i+1;j<=3;j++)                    for(int k=j+1;k<=4;k++)                            if(s>=((d[i]+1)*c[i]+(d[j]+1)*c[j]+(d[k]+1)*c[k]))                                ans-=f[s-((d[i]+1)*c[i]+(d[j]+1)*c[j]+(d[k]+1)*c[k])];        if(s>=((d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[3]+1)*c[3]+(d[4]+1)*c[4]))            ans+=f[s-((d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[3]+1)*c[3]+(d[4]+1)*c[4])];        printf("%lld\n",ans);    }    return 0;}

好看的dfs

#include<cstdio>#include<cstring>using namespace std;typedef long long LL;LL c[5],d[5],f[110000],ans;void dfs(int x,int k,int sum){    if(sum<0)return ;    if(x==5)    {        if(k%2==1)ans-=f[sum];        else ans+=f[sum];        return;    }    dfs(x+1,k+1,sum-(d[x]+1)*c[x]);    dfs(x+1,k,sum);}int main(){    for(int i=1;i<=4;i++)scanf("%d",&c[i]);    memset(f,0,sizeof(f));f[0]=1;    for(int i=1;i<=4;i++)        for(int j=c[i];j<=100000;j++)            f[j]+=f[j-c[i]];    int n,s;    scanf("%d",&n);    while(n--)    {        for(int i=1;i<=4;i++)scanf("%d",&d[i]);        scanf("%d",&s);        ans=0;dfs(1,0,s);        printf("%lld\n",ans);    }    return 0;}

By_yzh

2 4
原创粉丝点击