bzoj 1042: [HAOI2008]硬币购物
1042: [HAOI2008]硬币购物
Time Limit: 10 Sec Memory Limit: 162 MBDescription
硬币购物一共有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
HINT
Source
如果用裸的有限背包做,那么时间复杂度就上天了;
我们可以把它先当做无限背包预处理出来;
那么di个硬币的方案数就是 dp[s]-dp[s-(di+1)*ci];
如果有多个限制的硬币,那么会有重复;
运用容斥原理,只有4个数,暴力求解即可;
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define N 100000 using namespace std; int c[5],tot,s,d[5]; long long dp[N+8],num,res; void dfs(int u,int flag,int sum){ if(sum<0) return; if(u==5){ if(flag&1){ res-=dp[sum]; }else{ res+=dp[sum]; } return; } dfs(u+1,flag+1,sum-(d[u]+1)*c[u]); dfs(u+1,flag,sum); } int main(){ memset(dp,0,sizeof(dp)); scanf("%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&tot); dp[0]=1; for(int i=1;i<=4;i++) for(int j=c[i];j<=N;j++) dp[j]+=dp[j-c[i]]; for(int i=1;i<=tot;i++){ scanf("%d%d%d%d%d",&d[1],&d[2],&d[3],&d[4],&s); res=0; num=s; dfs(1,0,num); printf("%lld\n",res); } }