DP+容斥 BZOJ1042
Posted Billyshuai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DP+容斥 BZOJ1042相关的知识,希望对你有一定的参考价值。
1042: [HAOI2008]硬币购物
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2558 Solved: 1539
[Submit][Status][Discuss]
Description
硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买s
i的价值的东西。请问每次有多少种付款方法。
Input
第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000
Output
每次的方法数
Sample Input
1 2 5 10 2
3 2 3 1 10
1000 2 2 2 900
3 2 3 1 10
1000 2 2 2 900
Sample Output
4
27
27
佩服脑洞 http://www.cnblogs.com/zhuohan123/p/3284272.html
裸01背包(包括二进制分解),会造成重复计数 比如两个2元硬币 造成dp[2]=2。
也就是说同样数目的同种硬币本质是一样的,却重复计数了
如果每种硬币数目都是2^n-1的形式,应该就可以二进制分解了,但是这题显然不是=_=
#include<cstdio>
typedef long long ll;
int c[5];
ll dp[110000];
struct{long long operator[](const int &pos){return pos<0?0:dp[pos];}}f;
int main(){
int t;
scanf("%d%d%d%d%d",c+1,c+2,c+3,c+4,&t);
dp[0]=1;
for(int i=1;i<=4;++i)
for(int j=0;j<=100000;++j)
if(j+c[i]<=100000) dp[j+c[i]]+=dp[j];
while(t--){
int d[5],s;
scanf("%d%d%d%d%d",d+1,d+2,d+3,d+4,&s);
long long ans=f[s];
ans-=f[s-(d[1]+1)*c[1]];
ans-=f[s-(d[2]+1)*c[2]];
ans-=f[s-(d[3]+1)*c[3]];
ans-=f[s-(d[4]+1)*c[4]];
ans+=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]];
ans+=f[s-(d[1]+1)*c[1]-(d[3]+1)*c[3]];
ans+=f[s-(d[1]+1)*c[1]-(d[4]+1)*c[4]];
ans+=f[s-(d[2]+1)*c[2]-(d[3]+1)*c[3]];
ans+=f[s-(d[2]+1)*c[2]-(d[4]+1)*c[4]];
ans+=f[s-(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]];
ans-=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[4]+1)*c[4]];
ans-=f[s-(d[1]+1)*c[1]-(d[3]+1)*c[3]-(d[4]+1)*c[4]];
ans-=f[s-(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);
}
}
typedef long long ll;
int c[5];
ll dp[110000];
struct{long long operator[](const int &pos){return pos<0?0:dp[pos];}}f;
int main(){
int t;
scanf("%d%d%d%d%d",c+1,c+2,c+3,c+4,&t);
dp[0]=1;
for(int i=1;i<=4;++i)
for(int j=0;j<=100000;++j)
if(j+c[i]<=100000) dp[j+c[i]]+=dp[j];
while(t--){
int d[5],s;
scanf("%d%d%d%d%d",d+1,d+2,d+3,d+4,&s);
long long ans=f[s];
ans-=f[s-(d[1]+1)*c[1]];
ans-=f[s-(d[2]+1)*c[2]];
ans-=f[s-(d[3]+1)*c[3]];
ans-=f[s-(d[4]+1)*c[4]];
ans+=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]];
ans+=f[s-(d[1]+1)*c[1]-(d[3]+1)*c[3]];
ans+=f[s-(d[1]+1)*c[1]-(d[4]+1)*c[4]];
ans+=f[s-(d[2]+1)*c[2]-(d[3]+1)*c[3]];
ans+=f[s-(d[2]+1)*c[2]-(d[4]+1)*c[4]];
ans+=f[s-(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]];
ans-=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[4]+1)*c[4]];
ans-=f[s-(d[1]+1)*c[1]-(d[3]+1)*c[3]-(d[4]+1)*c[4]];
ans-=f[s-(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);
}
}
以上是关于DP+容斥 BZOJ1042的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1042: [HAOI2008]硬币购物容斥原理+dp
BZOJ-1042: [HAOI2008]硬币购物 (背包DP+容斥原理)