看到只有四种面额的硬币,以及每种硬币数量的限制,很容易想到容斥
我们用f[i]表示总面额为i且不考虑数量限制的方案数
则f[i]可以预处理出来
容斥时只需要令不合法的硬币数量为d[i]+1,然后计算f[s-(d[i]+1)*c[i]]即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 
  | #include<bits/stdc++.h> #define FILE "read" typedef long long ll; using namespace std; const int MAXN=(int)1e5,D=50; int s,a[10],c[10],d[10]; ll f[MAXN+D]; inline int read(){ 	int x=0,f=1;  char ch=getchar(); 	while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();} 	while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();} 	return x*f; } void pre(){ 	f[0]=1; 	for(int i=1;i<=4;++i) 		for(int j=c[i];j<=MAXN;++j) 			f[j]+=f[j-c[i]]; } void solve(){ 	ll ans=0; 	for(int i=1;i<=4;++i)  d[i]=read();  s=read(); 	for(int i=0;i<(1<<4);++i){ 		int cnt=0,temp=s; 		for(int j=1;j<=4;++j)if((1<<(j-1))&i)a[++cnt]=j; 		for(int j=1;j<=cnt;++j) temp-=(d[a[j]]+1)*c[a[j]]; 		if(temp<0)  continue; 		ans+=(cnt&1)?-f[temp]:f[temp]; 	} 	printf("%lld\n",ans); } int main(){ 	freopen(FILE".in","r",stdin); 	freopen(FILE".out","w",stdout); 	for(int i=1;i<=4;++i)  c[i]=read();  pre(); 	for(int T=read();T;--T)  solve(); 	return 0; } 
  | 
 
      
     
    
   
  
    
    
        本文标题:【bzoj1042】硬币购物
        文章作者:chty
        发布时间:2017年03月12日 - 19时53分
        最后更新:2018年03月02日 - 17时33分
        
        
             许可协议:本文为博主原创,未经许可不得转载。