硬币购物
如果是背包的话
这个时间复杂度不对
所以是容斥????
直接计算方案数不好计算,所以考虑补集转化,总共的方案数可以用完全背包预处理,就是设f[0]=1,以后不断+=就可以了,
那么不合法的方案呢,就是某些物品超出了数量限制。有可能一个超出限制,也有可能两个超出限制,所以是容斥
因为四个物品价值数量都不同,所以应该分开讨论
一个超出的有四种
两个超出的有六种......
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 const int maxn=1e5+7; 8 typedef long long ll; 9 ll t,s; 10 ll c[7],d[7],f[maxn]; 11 int main(){ 12 cin>>c[1]>>c[2]>>c[3]>>c[4]>>t; 13 f[0]=1; 14 for(int i=1;i<=4;i++) 15 for(int j=c[i];j<=maxn-5;j++) 16 f[j]+=f[j-c[i]]; 17 while(t--){ 18 cin>>d[1]>>d[2]>>d[3]>>d[4]>>s; 19 ll ret=f[s]; 20 if(s>=(d[1]+1)*c[1]) ret-=f[s-(d[1]+1)*c[1]]; 21 if(s>=(d[2]+1)*c[2]) ret-=f[s-(d[2]+1)*c[2]]; 22 if(s>=(d[3]+1)*c[3]) ret-=f[s-(d[3]+1)*c[3]]; 23 if(s>=(d[4]+1)*c[4]) ret-=f[s-(d[4]+1)*c[4]]; 24 if(s>=(d[1]+1)*c[1]+(d[2]+1)*c[2]) ret+=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]]; 25 if(s>=(d[1]+1)*c[1]+(d[3]+1)*c[3]) ret+=f[s-(d[1]+1)*c[1]-(d[3]+1)*c[3]]; 26 if(s>=(d[1]+1)*c[1]+(d[4]+1)*c[4]) ret+=f[s-(d[1]+1)*c[1]-(d[4]+1)*c[4]]; 27 if(s>=(d[2]+1)*c[2]+(d[3]+1)*c[3]) ret+=f[s-(d[2]+1)*c[2]-(d[3]+1)*c[3]]; 28 if(s>=(d[2]+1)*c[2]+(d[4]+1)*c[4]) ret+=f[s-(d[2]+1)*c[2]-(d[4]+1)*c[4]]; 29 if(s>=(d[3]+1)*c[3]+(d[4]+1)*c[4]) ret+=f[s-(d[3]+1)*c[3]-(d[4]+1)*c[4]]; 30 if(s>=(d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[3]+1)*c[3]) ret-=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[3]+1)*c[3]]; 31 if(s>=(d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[4]+1)*c[4]) ret-=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[4]+1)*c[4]]; 32 if(s>=(d[1]+1)*c[1]+(d[3]+1)*c[3]+(d[4]+1)*c[4]) ret-=f[s-(d[1]+1)*c[1]-(d[3]+1)*c[3]-(d[4]+1)*c[4]]; 33 if(s>=(d[2]+1)*c[2]+(d[3]+1)*c[3]+(d[4]+1)*c[4]) ret-=f[s-(d[2]+1)*c[2]-(d[3]+1)*c[3]-(d[4]+1)*c[4]]; 34 if(s>=(d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[3]+1)*c[3]+(d[4]+1)*c[4]) 35 ret+=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[3]+1)*c[3]-(d[4]+1)*c[4]]; 36 cout<<ret<<endl; 37 } 38 }
还有一种更加简单的,可以用二进制数来枚举哪些物品超出了限制:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 typedef long long ll; 8 const int maxn=1e5+7; 9 ll c[7],d[7],f[maxn]; 10 ll t,s,ans; 11 int main(){ 12 cin>>c[1]>>c[2]>>c[3]>>c[4]>>t; 13 f[0]=1; 14 /*for(ll i=1;i<=maxn-5;i++) 15 for(ll j=1;j<=4;j++) 16 if(i>=c[j]) f[i]+=f[i-c[j]];*/ 17 for(int i=1;i<=4;i++) 18 for(int j=c[i];j<=maxn-5;j++) 19 f[j]+=f[j-c[i]]; 20 while(t--){ 21 cin>>d[1]>>d[2]>>d[3]>>d[4]>>s; 22 ans=0; 23 for(ll i=0;i<=15;i++){ 24 ll ret=s,cnt=0; 25 for(ll j=1;j<=4;j++){ 26 if((i>>(j-1))&1){ 27 cnt^=1;ret-=c[j]*(d[j]+1); 28 } 29 } 30 if(ret<0) continue; 31 if(cnt) ans-=f[ret]; 32 else ans+=f[ret]; 33 } 34 cout<<ans<<endl; 35 } 36 }
背包的枚举顺序啊