BZOJ 1042:[HAOI2008]硬币购物 容斥原理 背包dp

来源:互联网 发布:霍元甲 歌词 知乎 编辑:程序博客网 时间:2024/05/20 18:54

1042: [HAOI2008]硬币购物

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2505  Solved: 1505
[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

Sample Output

4
27

把不需要限制硬币使用个数的搞出来

然后用容斥原理把超出限制的高出去


#include<ctime>#include<cmath>#include<cstdio>#include<cstring>#include<cstdlib>#include<complex>#include<iostream>#include<algorithm>#include<iomanip>#include<vector>#include<string>#include<queue>#include<map>#include<set>using namespace std;typedef long long ll;inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}return x*f;}const int N=100100;ll c[5],d[5],f[N];int main(){ll n,T;for(int i=1;i<=4;i++)c[i]=read();T=read();f[0]=1;for(int j=1;j<=4;j++)for(int i=c[j];i<=N;i++)f[i]+=f[i-c[j]];while(T--){for(int i=1;i<=4;i++)d[i]=read();n=read();ll ans=f[n];for(int i=1;i<=4;i++)if(n>=c[i]*(d[i]+1))ans-=f[n-c[i]*(d[i]+1)];for(int i=1;i<=4;i++)for(int j=i+1;j<=4;j++)if(n>=c[i]*(d[i]+1)+c[j]*(d[j]+1))ans+=f[n-c[i]*(d[i]+1)-c[j]*(d[j]+1)];for(int i=1;i<=4;i++)for(int j=i+1;j<=4;j++)for(int k=j+1;k<=4;k++)if(n>=c[i]*(d[i]+1)+c[j]*(d[j]+1)+c[k]*(d[k]+1))ans-=f[n-c[i]*(d[i]+1)-c[j]*(d[j]+1)-c[k]*(d[k]+1)];if(n>=c[1]*(d[1]+1)+c[2]*(d[2]+1)+c[3]*(d[3]+1)+c[4]*(d[4]+1))ans+=f[n-c[1]*(d[1]+1)-c[2]*(d[2]+1)-c[3]*(d[3]+1)-c[4]*(d[4]+1)];printf("%lld\n",ans);}return 0;}/*1 2 5 10 23 2 3 1 101000 2 2 2 900427*/


阅读全文
0 0